Files
nuzlocke-tracker/.beans/nuzlocke-tracker-t9aj--migrate-jwt-verification-from-hs256-shared-secret.md
Julian Tabel 177c02006a
All checks were successful
CI / backend-tests (pull_request) Successful in 28s
CI / frontend-tests (pull_request) Successful in 28s
feat: migrate JWT verification from HS256 shared secret to JWKS
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>
2026-03-21 14:01:36 +01:00

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.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).