Replace symmetric HS256 JWT verification with asymmetric RS256 using JWKS.
Backend now fetches and caches public keys from Supabase's JWKS endpoint
instead of using a shared secret.
- Add cryptography dependency for RS256 support
- Use PyJWKClient to fetch/cache JWKS from {SUPABASE_URL}/.well-known/jwks.json
- Remove SUPABASE_JWT_SECRET from config, docker-compose, deploy workflow, .env
- Update tests to use RS256 tokens with mocked JWKS client
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1.8 KiB
title, status, type, priority, created_at, updated_at
| title | status | type | priority | created_at | updated_at |
|---|---|---|---|---|---|
| Migrate JWT verification from HS256 shared secret to asymmetric keys (JWKS) | completed | task | low | 2026-03-21T11:14:29Z | 2026-03-21T13:01:33Z |
The backend currently verifies Supabase JWTs using an HS256 shared secret (SUPABASE_JWT_SECRET). Supabase recommends migrating to asymmetric keys (RS256) for better security.\n\nInstead of storing a shared secret, the backend would fetch public keys from Supabase's JWKS endpoint (https://<project>.supabase.co/.well-known/jwks.json) and verify tokens against those.\n\n## Changes needed\n\n- [x] Update backend/src/app/core/auth.py to fetch and cache JWKS public keys\n- [x] Change jwt.decode from HS256 to RS256 with the fetched public key\n- [x] Remove SUPABASE_JWT_SECRET from config, docker-compose, deploy workflow, and .env files\n- [x] Update tests\n\n## References\n\n- https://supabase.com/docs/guides/auth/signing-keys\n- https://supabase.com/docs/guides/auth/jwts
Summary of Changes
- Added
cryptography==45.0.3dependency for RS256 support - Updated
auth.pyto usePyJWKClientfor fetching and caching JWKS public keys from{SUPABASE_URL}/.well-known/jwks.json - Changed JWT verification from HS256 to RS256
- Removed
supabase_jwt_secretfrom config.py - Updated docker-compose.yml: removed
SUPABASE_JWT_SECRET, backend now uses JWKS from GoTrue URL - Updated docker-compose.prod.yml: replaced
SUPABASE_JWT_SECRETwithSUPABASE_URL - Updated deploy.yml: deploy workflow now writes
SUPABASE_URLinstead ofSUPABASE_JWT_SECRET - Updated .env.example files: removed
SUPABASE_JWT_SECRETreferences - Rewrote tests to use RS256 tokens with mocked JWKS client
Note: For production, add SUPABASE_URL to your GitHub secrets (should point to your Supabase project URL like https://your-project.supabase.co).