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:
@@ -79,3 +79,46 @@ def test_get_me_invalid_token(client):
|
||||
headers={"Authorization": "Bearer invalidtoken"},
|
||||
)
|
||||
assert response.status_code == 401
|
||||
|
||||
|
||||
def test_logout_revokes_token(client, admin_user):
|
||||
"""After logout, the same JWT must be rejected (Redis blacklist).
|
||||
|
||||
Prefer Authorization over the HttpOnly cookie so logout blacklists the
|
||||
same token the client sends on the next request; clear cookies to avoid
|
||||
stale jar state across calls.
|
||||
"""
|
||||
login = client.post(
|
||||
"/api/v1/auth/login",
|
||||
data={"username": "admin", "password": "admin123"},
|
||||
)
|
||||
assert login.status_code == 200
|
||||
token = login.json()["access_token"]
|
||||
|
||||
client.cookies.clear()
|
||||
out = client.post(
|
||||
"/api/v1/auth/logout",
|
||||
headers={"Authorization": f"Bearer {token}"},
|
||||
)
|
||||
assert out.status_code == 200
|
||||
|
||||
from jose import jwt
|
||||
|
||||
from app.config import settings
|
||||
from app.infrastructure.redis_client import get_redis_blacklist
|
||||
|
||||
payload = jwt.decode(
|
||||
token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM],
|
||||
)
|
||||
jti = payload.get("jti")
|
||||
assert jti
|
||||
assert get_redis_blacklist().exists(f"blacklist:{jti}")
|
||||
|
||||
client.cookies.clear()
|
||||
assert not len(client.cookies), "cookie jar must be empty to force Authorization Bearer"
|
||||
me = client.get(
|
||||
"/api/v1/auth/me",
|
||||
headers={"Authorization": f"Bearer {token}"},
|
||||
)
|
||||
assert me.status_code == 401
|
||||
assert me.json()["detail"] == "Token has been revoked"
|
||||
|
||||
Reference in New Issue
Block a user