Firebase Auth vs custom JWT: what we chose at CryptoPrism
We started with Firebase Auth because it's free, fast, and handles 90% of auth flows out of the box — email/password, Google sign-in, anonymous sessions. Six months in, we hit the wall: Firebase Auth doesn't support custom JWT claims without a Cloud Function workaround, and our permission model needed per-user, per-exchange rate limits that couldn't live in a Firebase token.
The decision was to keep Firebase Auth as the identity provider (login, MFA, session management) but issue our own JWTs from the FastAPI backend for all authorisation. Firebase handles "who you are" — our backend handles "what you can do."
This split is critical: Firebase Auth is optimised for identity, not authorisation. Trying to force authorisation into Firebase custom claims works until your permission model grows beyond roles (admin/user) into resource-level policies (can read Binance data but not write trades). The moment you need resource-level auth, you need your own token.
The migration took two weekends: one to add JWT endpoints to the API, one to update all clients. Firebase Auth tokens now map to internal user records, and our JWTs carry the actual permission payload — exchange limits, feature flags, API quota. We kept the Firebase login UX but replaced everything underneath.
The lesson: don't outsource authorisation to an identity provider. Use them for what they're good at (login flows, MFA, social auth) and own the authorisation layer yourself.