--- name: jwt_generate kind: function lang: go domain: infra version: "1.0.0" purity: impure signature: "func JWTGenerate(claims JWTClaims, secret string) (string, error)" description: "Codifica y firma un JWT con HMAC-SHA256 (HS256). Retorna el token en formato header.payload.signature. Setea IssuedAt automaticamente si viene en cero." tags: [jwt, auth, token, hmac, sign, infra] uses_functions: [] uses_types: [JWTClaims_go_infra] returns: [] returns_optional: false error_type: error_go_core imports: [crypto/hmac, crypto/sha256, encoding/base64, encoding/json, errors, time] params: - name: claims desc: "claims del JWT (sub, iss, aud, exp, iat, custom). Si IssuedAt es 0 se rellena con time.Now()" - name: secret desc: "clave HMAC para firmar. No debe estar vacia. Obtenerla de env var o pass_get, nunca hardcoded" output: "token JWT firmado en formato base64url header.payload.signature" tested: true tests: ["genera token valido con claims completas", "setea IssuedAt si viene en cero", "error si secret vacio"] test_file_path: "functions/infra/jwt_generate_test.go" file_path: "functions/infra/jwt_generate.go" --- ## Ejemplo ```go claims := JWTClaims{ Subject: "user-123", ExpiresAt: time.Now().Add(24 * time.Hour).Unix(), Custom: map[string]any{"role": "admin"}, } token, err := JWTGenerate(claims, os.Getenv("JWT_SECRET")) if err != nil { return err } w.Header().Set("Authorization", "Bearer " + token) ``` ## Notas Impura — usa `time.Now()` para el claim `iat` cuando no viene fijado. Implementa HS256 sin libreria externa (solo stdlib crypto/hmac + crypto/sha256). Solo soporta HS256: para RS256/ES256 se crearia una funcion separada. El secret debe tener al menos 256 bits de entropia (32+ bytes aleatorios) para resistencia real. NO apto para escenarios multi-servicio donde se necesita clave publica/privada — usa RS256 en ese caso.