feat(07.4-02): add _compute_fgp helper + extend create_access_token with fgp claim

- Add _compute_fgp(user_agent, accept_lang) helper returning 16-char hex
  HMAC-SHA256 fingerprint (D-04); uses existing hmac + hashlib imports
- Extend create_access_token signature with user_agent/accept_lang params
  (empty-string defaults for backward compatibility, D-05)
- Embed fgp claim in every issued access token payload
This commit is contained in:
curo1305
2026-06-06 21:54:47 +02:00
parent 8c817705b7
commit 25c9142fe0
+18 -2
View File
@@ -84,10 +84,25 @@ def validate_password_strength(password: str) -> None:
# ── JWT helpers ─────────────────────────────────────────────────────────────────
def create_access_token(user_id: str, role: str) -> str:
def _compute_fgp(user_agent: str, accept_lang: str) -> str:
"""Return 16-char hex fingerprint binding a token to its client context (D-04)."""
return hmac.new(
settings.secret_key.encode(),
(user_agent + accept_lang).encode(),
hashlib.sha256,
).hexdigest()[:16]
def create_access_token(
user_id: str,
role: str,
user_agent: str = "",
accept_lang: str = "",
) -> str:
"""Return a signed JWT access token.
Claims: sub=user_id, role=role, typ='access', exp=now+access_token_expire_minutes.
Claims: sub=user_id, role=role, typ='access', exp=now+access_token_expire_minutes,
fgp=fingerprint computed from client User-Agent + Accept-Language headers (D-05).
"""
now = datetime.now(timezone.utc)
payload = {
@@ -97,6 +112,7 @@ def create_access_token(user_id: str, role: str) -> str:
"iat": now,
"exp": now + timedelta(minutes=settings.access_token_expire_minutes),
"jti": str(uuid.uuid4()),
"fgp": _compute_fgp(user_agent, accept_lang),
}
private_pem = base64.b64decode(settings.jwt_private_key).decode()
return jwt.encode(payload, private_pem, algorithm="ES256")