Skip to content

Commit c570d42

Browse files
committed
fix: review findings -- null metadata coalescing, case-insensitive Bearer, yield fixture
1. metadata: payload.get('user_metadata', {}) returns None when key exists with null value. Changed to 'or {}' pattern so downstream code can safely index result['metadata']. 2. Bearer prefix: was case-sensitive ('Bearer '), now handles 'bearer ', 'BEARER ' etc. Defensive -- most callers never hit this but WebSocket handlers pass raw query params. 3. Test fixture: changed from return to yield so patches stay active for the full test lifetime (correct pytest pattern). 4. Added 2 tests: null metadata coalescing, case-insensitive Bearer. 281 tests pass (270 existing + 11 new).
1 parent 57122e5 commit c570d42

2 files changed

Lines changed: 16 additions & 3 deletions

File tree

backend/services/auth.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def verify_jwt(self, token: str) -> Dict[str, Any]:
3535
No network call required -- instant verification using HS256.
3636
Falls back to Supabase API call if JWT_SECRET is not configured.
3737
"""
38-
if token.startswith("Bearer "):
38+
if token.lower().startswith("bearer "):
3939
token = token[7:]
4040

4141
# local decode when secret is available (fast path, no network)
@@ -65,7 +65,7 @@ def _verify_local(self, token: str) -> Dict[str, Any]:
6565
return {
6666
"user_id": user_id,
6767
"email": payload.get("email"),
68-
"metadata": payload.get("user_metadata", {}),
68+
"metadata": payload.get("user_metadata") or {},
6969
}
7070

7171
except jwt.ExpiredSignatureError:

backend/tests/test_jwt_local_decode.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ def auth_service():
3030
"SUPABASE_JWT_SECRET": JWT_SECRET,
3131
}):
3232
from services.auth import SupabaseAuthService
33-
return SupabaseAuthService()
33+
yield SupabaseAuthService()
3434

3535

3636
class TestLocalJWTDecode:
@@ -100,6 +100,19 @@ def test_metadata_defaults_to_empty_dict(self, auth_service):
100100

101101
assert result["metadata"] == {}
102102

103+
def test_metadata_null_coalesced_to_empty_dict(self, auth_service):
104+
"""user_metadata can be explicitly null in Supabase JWTs."""
105+
token = _make_token({"sub": "user-null-meta", "user_metadata": None})
106+
result = auth_service.verify_jwt(token)
107+
108+
assert result["metadata"] == {}
109+
110+
def test_bearer_prefix_case_insensitive(self, auth_service):
111+
token = _make_token({"sub": "user-case"})
112+
for prefix in ["Bearer ", "bearer ", "BEARER "]:
113+
result = auth_service.verify_jwt(f"{prefix}{token}")
114+
assert result["user_id"] == "user-case"
115+
103116

104117
class TestAPIFallback:
105118
"""When JWT secret is not configured, fall back to Supabase API."""

0 commit comments

Comments
 (0)