From 4e72c842762325ed9b635140fce417f210755a39 Mon Sep 17 00:00:00 2001 From: zouantchaw <44246692+zouantchaw@users.noreply.github.com> Date: Tue, 17 Mar 2026 13:44:45 +0100 Subject: [PATCH] docs(auth): document v2 auth flows and refresh --- docs/BACKEND/API_GUIDES/V2/README.md | 1 + docs/BACKEND/API_GUIDES/V2/authentication.md | 343 +++++++++++++++++++ docs/BACKEND/API_GUIDES/V2/unified-api.md | 2 + 3 files changed, 346 insertions(+) create mode 100644 docs/BACKEND/API_GUIDES/V2/authentication.md diff --git a/docs/BACKEND/API_GUIDES/V2/README.md b/docs/BACKEND/API_GUIDES/V2/README.md index c9964d51..2025ab4e 100644 --- a/docs/BACKEND/API_GUIDES/V2/README.md +++ b/docs/BACKEND/API_GUIDES/V2/README.md @@ -141,6 +141,7 @@ Those routes still exist for backend/internal compatibility, but mobile/frontend ## 7) Docs +- [Authentication](./authentication.md) - [Unified API](./unified-api.md) - [Core API](./core-api.md) - [Command API](./command-api.md) diff --git a/docs/BACKEND/API_GUIDES/V2/authentication.md b/docs/BACKEND/API_GUIDES/V2/authentication.md new file mode 100644 index 00000000..d90e585a --- /dev/null +++ b/docs/BACKEND/API_GUIDES/V2/authentication.md @@ -0,0 +1,343 @@ +# V2 Authentication Guide + +This document is the source of truth for V2 authentication. + +Base URL: + +```env +API_V2_BASE_URL=https://krow-api-v2-933560802882.us-central1.run.app +``` + +## 1) What is implemented + +### Client app + +Client authentication is implemented through backend endpoints: + +- `POST /auth/client/sign-in` +- `POST /auth/client/sign-up` +- `POST /auth/client/sign-out` +- `GET /auth/session` + +The backend signs the user in with Firebase Identity Toolkit, validates the user against the V2 database, and returns the full auth envelope. + +### Staff app + +Staff authentication is implemented, but it is a hybrid flow. + +Routes: + +- `POST /auth/staff/phone/start` +- `POST /auth/staff/phone/verify` +- `POST /auth/staff/sign-out` +- `GET /auth/session` + +Important: + +- the default mobile path is **not** a fully backend-managed OTP flow +- the usual mobile path uses the Firebase Auth SDK on-device for phone verification +- after the device gets a Firebase `idToken`, frontend sends that token to `POST /auth/staff/phone/verify` + +So if someone expects `POST /auth/staff/phone/start` to always send the SMS and always return `sessionInfo`, that expectation is wrong for the current implementation + +## 2) Auth refresh + +There is currently **no** backend `/auth/refresh` endpoint. + +That is intentional for now. + +Current refresh model: + +- frontend keeps Firebase Auth local session state +- frontend lets the Firebase SDK refresh the ID token +- frontend sends the latest Firebase ID token in: + +```http +Authorization: Bearer +``` + +Use: + +- `authStateChanges()` / `idTokenChanges()` listeners +- `currentUser.getIdToken()` +- `currentUser.getIdToken(true)` only when a forced refresh is actually needed + +`GET /auth/session` is **not** a refresh endpoint. + +It is a context endpoint used to: + +- hydrate role/tenant/business/staff context +- validate that the signed-in Firebase user is allowed in this app + +## 3) Client auth flow + +### Client sign-in + +Request: + +```http +POST /auth/client/sign-in +Content-Type: application/json +``` + +```json +{ + "email": "legendary.owner+v2@krowd.com", + "password": "Demo2026!" +} +``` + +Response: + +```json +{ + "sessionToken": "firebase-id-token", + "refreshToken": "firebase-refresh-token", + "expiresInSeconds": 3600, + "user": { + "id": "user-uuid", + "email": "legendary.owner+v2@krowd.com", + "displayName": "Legendary Owner", + "phone": null + }, + "tenant": { + "tenantId": "tenant-uuid", + "tenantName": "Legendary Event Staffing and Entertainment" + }, + "business": { + "businessId": "business-uuid", + "businessName": "Google Mountain View Cafes" + }, + "requestId": "uuid" +} +``` + +Frontend behavior: + +1. Call `POST /auth/client/sign-in` +2. If success, sign in locally with Firebase Auth SDK using the same email/password +3. Use Firebase SDK token refresh for later API calls +4. Use `GET /auth/session` when role/session hydration is needed on app boot + +### Client sign-up + +Request: + +```http +POST /auth/client/sign-up +Content-Type: application/json +``` + +```json +{ + "companyName": "Legendary Event Staffing and Entertainment", + "email": "legendary.owner+v2@krowd.com", + "password": "Demo2026!" +} +``` + +What it does: + +- creates Firebase Auth account +- creates V2 user +- creates tenant +- creates business +- creates tenant membership +- creates business membership + +Frontend behavior after success: + +1. call `POST /auth/client/sign-up` +2. sign in locally with Firebase Auth SDK using the same email/password +3. use Firebase SDK for later token refresh + +## 4) Staff auth flow + +## Step 1: start phone auth + +Request: + +```http +POST /auth/staff/phone/start +Content-Type: application/json +``` + +```json +{ + "phoneNumber": "+15551234567" +} +``` + +Possible response A: + +```json +{ + "mode": "CLIENT_FIREBASE_SDK", + "provider": "firebase-phone-auth", + "phoneNumber": "+15551234567", + "nextStep": "Complete phone verification in the mobile client, then call /auth/staff/phone/verify with the Firebase idToken.", + "requestId": "uuid" +} +``` + +This is the normal mobile path when frontend does **not** send recaptcha or integrity tokens. + +Possible response B: + +```json +{ + "mode": "IDENTITY_TOOLKIT_SMS", + "phoneNumber": "+15551234567", + "sessionInfo": "firebase-session-info", + "requestId": "uuid" +} +``` + +This is the server-managed SMS path. + +## Step 2A: normal mobile path (`CLIENT_FIREBASE_SDK`) + +Frontend must do this on-device: + +1. call `FirebaseAuth.verifyPhoneNumber(...)` +2. collect the `verificationId` +3. collect the OTP code from the user +4. create a Firebase phone credential +5. call `signInWithCredential(...)` +6. get Firebase `idToken` +7. call `POST /auth/staff/phone/verify` with that `idToken` + +Request: + +```http +POST /auth/staff/phone/verify +Content-Type: application/json +``` + +```json +{ + "mode": "sign-in", + "idToken": "firebase-id-token-from-device" +} +``` + +Response: + +```json +{ + "sessionToken": "firebase-id-token-from-device", + "refreshToken": null, + "expiresInSeconds": 3600, + "user": { + "id": "user-uuid", + "phone": "+15551234567" + }, + "staff": { + "staffId": "staff-uuid" + }, + "requiresProfileSetup": false, + "requestId": "uuid" +} +``` + +Important: + +- `refreshToken` is expected to be `null` in this path +- refresh remains owned by Firebase Auth SDK on the device + +## Step 2B: server SMS path (`IDENTITY_TOOLKIT_SMS`) + +If `start` returned `sessionInfo`, frontend can call: + +```json +{ + "mode": "sign-in", + "sessionInfo": "firebase-session-info", + "code": "123456" +} +``` + +The backend exchanges `sessionInfo + code` with Identity Toolkit and returns the hydrated auth envelope. + +## 5) Sign-out + +Routes: + +- `POST /auth/sign-out` +- `POST /auth/client/sign-out` +- `POST /auth/staff/sign-out` + +All sign-out routes require: + +```http +Authorization: Bearer +``` + +What sign-out does: + +- revokes backend-side Firebase sessions for that user +- frontend should still clear local Firebase Auth state with `FirebaseAuth.instance.signOut()` + +## 6) Session endpoint + +Route: + +- `GET /auth/session` + +Headers: + +```http +Authorization: Bearer +``` + +Use it for: + +- app startup hydration +- role validation +- deciding whether this app should allow the current signed-in user + +Do not use it as: + +- a refresh endpoint +- a login endpoint + +## 7) Error contract + +All auth routes use the standard V2 error envelope: + +```json +{ + "code": "STRING_CODE", + "message": "Human readable message", + "details": {}, + "requestId": "uuid" +} +``` + +Common auth failures: + +- `UNAUTHENTICATED` +- `FORBIDDEN` +- `VALIDATION_ERROR` +- `AUTH_PROVIDER_ERROR` + +## 8) Troubleshooting + +### Staff sign-in does not work, but endpoints are reachable + +The most likely causes are: + +1. frontend expected `POST /auth/staff/phone/start` to always return `sessionInfo` +2. frontend did not complete Firebase phone verification on-device +3. frontend called `POST /auth/staff/phone/verify` without a valid Firebase `idToken` +4. frontend phone-auth setup in Firebase mobile config is incomplete + +### `POST /auth/staff/phone/start` returns `CLIENT_FIREBASE_SDK` + +That is expected for the normal mobile flow when no recaptcha or integrity tokens are sent. + +### There is no `/auth/refresh` + +That is also expected right now. + +Refresh is handled by Firebase Auth SDK on the client. diff --git a/docs/BACKEND/API_GUIDES/V2/unified-api.md b/docs/BACKEND/API_GUIDES/V2/unified-api.md index 079ec8ab..c9778dea 100644 --- a/docs/BACKEND/API_GUIDES/V2/unified-api.md +++ b/docs/BACKEND/API_GUIDES/V2/unified-api.md @@ -8,6 +8,8 @@ The gateway keeps backend services separate internally, but frontend should trea ## 1) Auth routes +Full auth behavior, including staff phone flow and refresh rules, is documented in [Authentication](./authentication.md). + ### Client auth - `POST /auth/client/sign-in`