Auth0 Identity + Firestore
This suite already uses Firestore under the hood — firebase-admin backs session storage for the Anonymous Sessions and cart demos. This page surfaces that same credential as its own pattern: the Auth0 sub claim used as a stable foreign key into Firestore, for both authorization data (who can access an account, with what role) and an actor-attributed audit trail. No new Auth0 application, no new Firebase project — just the already-configured firebase-admin credentials, used visibly instead of invisibly.
Auth0
Issues session, sub claim
Real tenant
This app
Server-only, firebase-admin
Firestore
accounts/{id}/memberships/{sub}
What this isn't: this is not Firebase Hosting (no app is deployed on Firebase here) and not Firebase Authentication (Auth0 remains the only identity provider). Firestore is used purely as this demo's data layer, reached exclusively through the server-side Admin SDK — see Security Implications below for why that matters.
More detail, including four real bugs an adversarial review caught in this already-shipped code.
Checking session…
Strengths
- The Auth0 sub claim is a stable, non-reassignable identifier — safe to use as a long-lived foreign key into another system's data, unlike email (which can change) or name (which was never unique to begin with).
- All Firestore access here goes through the Admin SDK on the server, never a client-side Firestore SDK with its own security rules — so there is exactly one place (this app's own API routes) that can reach this data at all, not a rules engine trying to replicate the same authorization logic a second time.
- Role data and the audit trail live outside the token entirely — a user's access can be revoked or changed by editing one Firestore document, with no token to revoke, no re-login required, and no stale-claim problem to worry about.
Risks & Considerations
- The Admin SDK bypasses Firestore Security Rules completely — rules are a client-SDK concept and provide zero protection here. This pattern makes Firestore an *implicit* authorization store: nothing at the database layer stops a future code path from reading or writing accounts/* directly instead of going through the one shared membership-lookup function.
- The audit log is only as trustworthy as every call site actually remembering to write to it — there is no database trigger or constraint enforcing that a state-changing action gets logged; a new code path that forgets to call it fails silently, with no audit record and no error.
- A membership document and a revoked/expired Auth0 session are two independent things that can drift out of sync — deleting a user's Auth0 account does not automatically remove their Firestore membership record, and vice versa.
Hardening Checklist
- Centralize every read/write of accounts/* behind one shared module (this demo's lib/firestore-memberships.ts) rather than letting individual routes call db.collection("accounts") directly — that's the only real enforcement boundary this pattern has, since Firestore itself enforces nothing on the Admin SDK path.
- If this ever needs to scale beyond a server-trusted backend — e.g. a mobile app talking to Firestore directly — revisit whether real Firestore Security Rules plus the client SDK would structurally enforce the same boundary this demo currently only enforces by convention.
- Treat the sub-keyed document as the source of truth for authorization, and treat anything cached from it (a session claim, a UI state) as advisory only — always re-check Firestore for the state-changing action itself, not just for rendering.