"""JWT encode/decode round-trips.""" from __future__ import annotations from datetime import datetime, timedelta, timezone import jwt as pyjwt import pytest from notify_bridge_server.auth.jwt import ( ALGORITHM, create_access_token, create_refresh_token, decode_token, ) from notify_bridge_server.config import settings def test_access_token_round_trip() -> None: token = create_access_token(user_id=1, role="admin", token_version=3) payload = decode_token(token) assert payload["sub"] == "1" assert payload["type"] == "access" assert payload["role"] == "admin" assert payload["ver"] == 3 assert payload["iss"] == settings.jwt_issuer assert payload["aud"] == settings.jwt_audience def test_refresh_token_round_trip() -> None: token = create_refresh_token(user_id=7, token_version=2) payload = decode_token(token) assert payload["type"] == "refresh" assert payload["sub"] == "7" def test_decode_rejects_wrong_audience() -> None: """A token signed with our key but for a different audience is rejected.""" now = datetime.now(timezone.utc) forged = pyjwt.encode( { "iss": settings.jwt_issuer, "aud": "other-service", "sub": "1", "type": "access", "ver": 1, "iat": now, "exp": now + timedelta(minutes=5), }, settings.secret_key, algorithm=ALGORITHM, ) with pytest.raises(pyjwt.InvalidAudienceError): decode_token(forged) def test_decode_rejects_none_alg() -> None: """An ``alg: none`` token must never be accepted.""" now = datetime.now(timezone.utc) forged = pyjwt.encode( { "iss": settings.jwt_issuer, "aud": settings.jwt_audience, "sub": "1", "type": "access", "ver": 1, "iat": now, "exp": now + timedelta(minutes=5), }, "", algorithm="none", ) with pytest.raises(pyjwt.InvalidAlgorithmError): decode_token(forged)