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.

Architecture — Auth0 Identity as a Firestore Foreign Key

Auth0

Issues session, sub claim

Real tenant

This app

Server-only, firebase-admin

Firestore

accounts/{id}/memberships/{sub}

1You sign in via whichever Auth0 session this suite already has active — no new Auth0 application for this demo.
2The server looks up accounts/acme-demo/memberships/{sub} using your Auth0 sub as the document ID — the foreign key, not the token itself.
3Your resolved role (owner/member/viewer) decides what the UI shows — the role lives in Firestore, not in any token claim.
4Triggering an action writes to accounts/acme-demo/auditLog with your sub and role attached — a real, actor-attributed record, not a mocked one.

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…

Security Implications

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.