feat: jwt_generate, jwt_validate, password_hash, password_verify
Fase 2 del issue 0010 — auth core: - jwt_generate/validate: HS256 manual con crypto/hmac + crypto/sha256 - password_hash/verify: wrappers de golang.org/x/crypto/bcrypt (cost 12 default) - JWT rechaza alg != HS256 para mitigar ataque 'alg=none' - hmac.Equal para comparacion constant-time de firmas
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
---
|
||||
name: jwt_validate
|
||||
kind: function
|
||||
lang: go
|
||||
domain: infra
|
||||
version: "1.0.0"
|
||||
purity: impure
|
||||
signature: "func JWTValidate(token string, secret string) (JWTClaims, error)"
|
||||
description: "Verifica la firma HMAC-SHA256 de un JWT y decodifica sus claims. Rechaza tokens mal formados, con firma invalida o expirados."
|
||||
tags: [jwt, auth, token, hmac, verify, infra]
|
||||
uses_functions: []
|
||||
uses_types: [JWTClaims_go_infra]
|
||||
returns: [JWTClaims_go_infra]
|
||||
returns_optional: false
|
||||
error_type: error_go_core
|
||||
imports: [crypto/hmac, crypto/sha256, encoding/base64, encoding/json, errors, strings, time]
|
||||
params:
|
||||
- name: token
|
||||
desc: "JWT string en formato header.payload.signature (base64url, sin padding)"
|
||||
- name: secret
|
||||
desc: "clave HMAC usada para firmar el token. Debe coincidir con la usada en JWTGenerate"
|
||||
output: "claims decodificadas si el token es valido; error si firma invalida, expirado o malformado"
|
||||
tested: true
|
||||
tests: ["valida token generado por JWTGenerate", "rechaza firma invalida", "rechaza token expirado", "rechaza token malformado", "rechaza algoritmo distinto de HS256"]
|
||||
test_file_path: "functions/infra/jwt_validate_test.go"
|
||||
file_path: "functions/infra/jwt_validate.go"
|
||||
---
|
||||
|
||||
## Ejemplo
|
||||
|
||||
```go
|
||||
auth := r.Header.Get("Authorization")
|
||||
token := strings.TrimPrefix(auth, "Bearer ")
|
||||
claims, err := JWTValidate(token, os.Getenv("JWT_SECRET"))
|
||||
if err != nil {
|
||||
HTTPErrorResponse(w, HTTPError{Status: 401, Code: "invalid_token", Message: err.Error()})
|
||||
return
|
||||
}
|
||||
userID := claims.Subject
|
||||
role, _ := claims.Custom["role"].(string)
|
||||
```
|
||||
|
||||
## Notas
|
||||
|
||||
Impura — usa `time.Now()` para comparar contra `exp`. Usa `hmac.Equal` para comparacion constant-time de firmas (mitiga timing attacks). Solo acepta alg=HS256 en el header, otros algoritmos se rechazan explicitamente para evitar el ataque "alg=none". Si `exp` es 0 (no fijado) no se valida expiracion — es responsabilidad del caller asegurar que sus tokens siempre tengan exp fijado. Errores descriptivos con prefijo `jwt_validate:` para facilitar debugging; en respuestas HTTP conviene mapear todos a un mensaje generico "token invalido" para no filtrar informacion.
|
||||
Reference in New Issue
Block a user