Skip to content

Commit 026b5b3

Browse files
committed
add auth documentation
1 parent 2f395e1 commit 026b5b3

File tree

1 file changed

+107
-0
lines changed

1 file changed

+107
-0
lines changed

docs/Authentication.md

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
# Authentication Architecture (SSR + IAP via GCIP)
2+
3+
This document explains how server-side authentication works in the Mobility Database Web app when calling the Mobility Feed API behind Google Cloud IAP with Identity Platform (GCIP). It also covers local development without Firebase access.
4+
5+
## Overview
6+
- Server components/actions call the Mobility Feed API using a server‑minted GCIP ID token.
7+
- The client never forwards its token to the server; all API calls use server credentials only.
8+
- Firebase Admin is initialized once via a centralized helper and used for both Remote Config and token minting.
9+
- Mock mode (MSW) enables local development without hitting the real API or Firebase.
10+
11+
## Server‑Side Token Flow (IAP + Identity Platform)
12+
1. Firebase Admin creates a **custom token** for a service UID (synthetic user identity).
13+
2. The custom token is exchanged with **Identity Toolkit** (`accounts:signInWithCustomToken`) to obtain a **GCIP ID token**.
14+
3. The GCIP ID token is added as `Authorization: Bearer <token>` for calls to the IAP‑protected Mobility Feed API.
15+
4. Tokens are cached server‑side and refreshed a few minutes before expiry.
16+
17+
Key code paths:
18+
- `src/lib/firebase-admin.ts`: centralized Admin initialization (`getFirebaseAdminApp()`), backed by `ensureAdminInitialized()`.
19+
- `src/app/utils/auth-server.ts`: token functions `getGcipIdToken()` and `getSSRAccessToken()` (the canonical token provider for SSR calls).
20+
- `src/app/services/feeds/index.ts`: OpenAPI client; injects `Authorization` header using the token returned by `getSSRAccessToken()`.
21+
22+
## Firebase Admin Initialization
23+
Centralized in `getFirebaseAdminApp()`:
24+
- Reuse existing Admin app if already initialized (matching `NEXT_PUBLIC_FIREBASE_PROJECT_ID`).
25+
- Prefer **inline service account JSON**: `GOOGLE_SA_JSON` (or `FIREBASE_SERVICE_ACCOUNT_JSON` if enabled in your environment).
26+
- Or load **from file path**: `GOOGLE_SA_JSON_PATH` (or `GOOGLE_APPLICATION_CREDENTIALS`).
27+
- Fail fast if no credentials are provided to avoid unpredictable ADC/metadata lookups in serverless/dev environments.
28+
29+
Required service account fields: `project_id`, `client_email`, `private_key`.
30+
31+
## Environment Variables
32+
Server‑side credentials and config (server‑only):
33+
- `GOOGLE_SA_JSON`: Inline service account JSON string.
34+
- `GOOGLE_SA_JSON_PATH`: Absolute/relative path to service account JSON file.
35+
- `NEXT_PUBLIC_FIREBASE_PROJECT_ID`: Project ID; used to match Admin apps and as fallback when JSON lacks `project_id`.
36+
37+
GCIP / Identity Toolkit:
38+
- `GCIP_API_KEY` (or `FIREBASE_API_KEY` or `NEXT_PUBLIC_FIREBASE_API_KEY`): API key for `accounts:signInWithCustomToken`.
39+
- `GCIP_TENANT_ID` (optional): Tenant ID when using multi‑tenant Identity Platform.
40+
- `GCIP_SERVICE_UID` (optional): Synthetic UID for the server caller (default: `iap-service-caller`).
41+
42+
Mock/dev:
43+
- `NEXT_PUBLIC_API_MOCKING=enabled`: Enables MSW mock service worker in the browser.
44+
- `LOCAL_DEV_NO_ADMIN=1` (optional): Bypass Admin initialization for Remote Config/token code paths during local experimentation.
45+
46+
## Remote Config
47+
- Server‑side code fetches Firebase Remote Config via Admin SDK.
48+
- In mock mode, Remote Config returns defaults to avoid Admin calls.
49+
- Entry points: `src/lib/remote-config.server.ts` and the `Providers` wrapper in `src/app/providers.tsx`.
50+
51+
## Mock Mode (No Real API or Firebase)
52+
Use **MSW** (Mock Service Worker) so mocks behave like a real API without changing app logic.
53+
54+
Setup:
55+
1. Initialize the worker (one‑time):
56+
```bash
57+
npx msw init public/
58+
```
59+
2. Start dev in mock mode:
60+
```bash
61+
NEXT_PUBLIC_API_MOCKING=enabled yarn start:dev:mock
62+
```
63+
3. Mock handlers live in `src/mocks/handlers.ts`.
64+
- The browser worker starts from `src/mocks/browser.ts` via `src/app/providers.tsx` when mock mode is enabled.
65+
66+
## Usage in Code
67+
- SSR/API calls: Always obtain `accessToken = await getSSRAccessToken()` in server components/actions, then pass to `openapi-fetch` client.
68+
- Do **not** forward client tokens to the server.
69+
- Keep all credentials server‑only and never expose service account JSON to client code.
70+
71+
## Security Considerations
72+
- **No client token pass‑through**: Prevents elevation of privilege and token replay.
73+
- **Server‑only credentials**: Service account material must never be sent to the client.
74+
- **Optional auditing**: You may forward end‑user identity headers (e.g., `X-User-Subject`, `X-User-Email`) for backend audit trails if required.
75+
76+
## Troubleshooting
77+
Common issues and fixes:
78+
- "Firebase app already exists": Multiple Admin initializations. Use centralized `getFirebaseAdminApp()` and reuse existing apps.
79+
- "Invalid GCIP ID token": IAP configured with Identity Platform requires **GCIP tokens**, not Google OIDC tokens.
80+
- Metadata errors (ENOTFOUND): ADC fallback on local/dev without credentials. Provide explicit service account JSON/path and avoid metadata server.
81+
- Missing fields: Ensure service account JSON contains `project_id`, `client_email`, `private_key`.
82+
- MSW not intercepting: Confirm `NEXT_PUBLIC_API_MOCKING=enabled`, `public/mockServiceWorker.js` exists, and the worker starts in `providers.tsx`.
83+
84+
## Quick Start (Local Dev)
85+
1. Provide service account (either inline or file path):
86+
- Inline (recommended for Vercel server env):
87+
- Set `GOOGLE_SA_JSON` to a single‑line JSON string.
88+
- File path:
89+
- Set `GOOGLE_SA_JSON_PATH` to the JSON file path.
90+
2. Start dev:
91+
```bash
92+
yarn start:dev
93+
```
94+
3. Optional mock mode:
95+
```bash
96+
npx msw init public/
97+
NEXT_PUBLIC_API_MOCKING=enabled yarn start:dev:mock
98+
```
99+
100+
## Deployment (Vercel)
101+
- Set server‑only env vars in Vercel:
102+
- `GOOGLE_SA_JSON`, `GCIP_API_KEY`, and optionally `GCIP_TENANT_ID`, `GCIP_SERVICE_UID`.
103+
- Ensure `NEXT_PUBLIC_FIREBASE_PROJECT_ID` matches your Firebase project.
104+
- Use Node runtime for server components/actions (default in Next.js 16 App Router).
105+
106+
---
107+
For questions or improvements, see `src/lib/firebase-admin.ts`, `src/app/utils/auth-server.ts`, and `src/mocks/handlers.ts` for practical references.

0 commit comments

Comments
 (0)