Marked as helpful by the asker
Rolling your own JWT is where most of the risk is. Three findings: the secret is hardcoded in config.py (move to env), tokens never expire (exp missing), and /users/{id} returns any user given any valid token (compare id with the token's sub). Consider dropping the custom auth for Supabase Auth or Auth0 and keep FastAPI for the domain logic.