feat(auth): move JWT blacklist to Redis with TTL [FASE-0.2]
Revoke tokens by jti in a dedicated Redis DB, honor TTL from JWT exp on logout, reject revoked tokens in get_current_user, and add FakeRedis-backed API tests.
This commit is contained in:
@@ -96,13 +96,26 @@ def logout(
|
||||
The token's ``jti`` is added to the Redis blacklist so it cannot
|
||||
be reused even if the cookie has already been copied elsewhere.
|
||||
The blacklist entry auto-expires when the token's ``exp`` is reached.
|
||||
|
||||
When both HttpOnly cookie and ``Authorization: Bearer`` are present
|
||||
(typical for API clients), **both** are revoked so the session cannot
|
||||
survive on whichever credential the next request prefers.
|
||||
"""
|
||||
# Attempt to blacklist the token's jti
|
||||
token = aegis_token or request.headers.get("Authorization", "").removeprefix("Bearer ").strip()
|
||||
if token:
|
||||
bearer = (
|
||||
request.headers.get("Authorization")
|
||||
or request.headers.get("authorization")
|
||||
or ""
|
||||
)
|
||||
bearer = bearer.removeprefix("Bearer ").removeprefix("bearer ").strip()
|
||||
|
||||
seen: set[str] = set()
|
||||
for raw in (aegis_token, bearer):
|
||||
if not raw or raw in seen:
|
||||
continue
|
||||
seen.add(raw)
|
||||
try:
|
||||
payload = jwt.decode(
|
||||
token,
|
||||
raw,
|
||||
settings.SECRET_KEY,
|
||||
algorithms=[settings.ALGORITHM],
|
||||
)
|
||||
@@ -111,7 +124,7 @@ def logout(
|
||||
if jti:
|
||||
blacklist_token(jti, float(exp))
|
||||
except JWTError:
|
||||
pass # token already invalid — nothing to revoke
|
||||
pass # token already invalid — nothing to revoke for this raw value
|
||||
|
||||
response.delete_cookie(
|
||||
key=_COOKIE_NAME,
|
||||
|
||||
Reference in New Issue
Block a user