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>
27 lines
1.8 KiB
Markdown
27 lines
1.8 KiB
Markdown
---
|
|
# nuzlocke-tracker-t9aj
|
|
title: Migrate JWT verification from HS256 shared secret to asymmetric keys (JWKS)
|
|
status: completed
|
|
type: task
|
|
priority: low
|
|
created_at: 2026-03-21T11:14:29Z
|
|
updated_at: 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.3` dependency for RS256 support
|
|
- Updated `auth.py` to use `PyJWKClient` for fetching and caching JWKS public keys from `{SUPABASE_URL}/.well-known/jwks.json`
|
|
- Changed JWT verification from HS256 to RS256
|
|
- Removed `supabase_jwt_secret` from 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_SECRET` with `SUPABASE_URL`
|
|
- Updated deploy.yml: deploy workflow now writes `SUPABASE_URL` instead of `SUPABASE_JWT_SECRET`
|
|
- Updated .env.example files: removed `SUPABASE_JWT_SECRET` references
|
|
- 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`).
|