7.1 KiB
V2 Authentication Guide
This document is the source of truth for V2 authentication.
Base URL:
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-inPOST /auth/client/sign-upPOST /auth/client/sign-outGET /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/startPOST /auth/staff/phone/verifyPOST /auth/staff/sign-outGET /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 toPOST /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:
Authorization: Bearer <firebase-id-token>
Use:
authStateChanges()/idTokenChanges()listenerscurrentUser.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:
POST /auth/client/sign-in
Content-Type: application/json
{
"email": "legendary.owner+v2@krowd.com",
"password": "Demo2026!"
}
Response:
{
"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:
- Call
POST /auth/client/sign-in - If success, sign in locally with Firebase Auth SDK using the same email/password
- Use Firebase SDK token refresh for later API calls
- Use
GET /auth/sessionwhen role/session hydration is needed on app boot
Client sign-up
Request:
POST /auth/client/sign-up
Content-Type: application/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:
- call
POST /auth/client/sign-up - sign in locally with Firebase Auth SDK using the same email/password
- use Firebase SDK for later token refresh
4) Staff auth flow
Step 1: start phone auth
Request:
POST /auth/staff/phone/start
Content-Type: application/json
{
"phoneNumber": "+15551234567"
}
Possible response A:
{
"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:
{
"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:
- call
FirebaseAuth.verifyPhoneNumber(...) - collect the
verificationId - collect the OTP code from the user
- create a Firebase phone credential
- call
signInWithCredential(...) - get Firebase
idToken - call
POST /auth/staff/phone/verifywith thatidToken
Request:
POST /auth/staff/phone/verify
Content-Type: application/json
{
"mode": "sign-in",
"idToken": "firebase-id-token-from-device"
}
Response:
{
"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:
refreshTokenis expected to benullin 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:
{
"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-outPOST /auth/client/sign-outPOST /auth/staff/sign-out
All sign-out routes require:
Authorization: Bearer <firebase-id-token>
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:
Authorization: Bearer <firebase-id-token>
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:
{
"code": "STRING_CODE",
"message": "Human readable message",
"details": {},
"requestId": "uuid"
}
Common auth failures:
UNAUTHENTICATEDFORBIDDENVALIDATION_ERRORAUTH_PROVIDER_ERROR
8) Troubleshooting
Staff sign-in does not work, but endpoints are reachable
The most likely causes are:
- frontend expected
POST /auth/staff/phone/startto always returnsessionInfo - frontend did not complete Firebase phone verification on-device
- frontend called
POST /auth/staff/phone/verifywithout a valid FirebaseidToken - 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.