Exchange server-held client credentials for a member's Firebase custom token.
Use this API from your authenticated backend. GOFA must enable member sign-in
for your tenant and enroll the supplied client secret for the external_user
grant. An arbitrary existing API credential does not automatically have this permission.
| Environment | Base URL |
|---|---|
| UAT | https://www.uat.gofa.app |
| Production | https://www.gofa.app |
Use the matching environment's client ID and secret. Send requests directly to the canonical HTTPS host so a redirect does not alter the POST or its credentials.
POST /api/auth/custom-token
Content-Type: application/json{
"grantType": "external_user",
"clientId": "your-client-id",
"clientSecret": "<server-only-client-secret>",
"externalUserId": "<existing-member-id>"
}Derive externalUserId from your verified member session. Never trust a member ID
submitted by the app without checking that session. Keep the existing ID unchanged.
Do not send an Authorization or ClientToken header with the direct credential pair.
The success response contains customToken and user. Read customToken and
return only that field to the same authenticated app session with
Cache-Control: no-store. Never return the client secret or ClientToken.
{"customToken": "<fresh-firebase-custom-token>"}If your backend prefers a temporary token, first obtain one with an explicit member-sign-in scope:
POST /api/client/token
Content-Type: application/json{
"clientId": "your-client-id",
"clientSecret": "<server-only-client-secret>",
"scope": "external_user"
}The response includes token, apiKeyId, scope and expiresAt. This ClientToken
lasts 15 minutes and authorizes member sign-in only. It cannot access tenant
admin/data APIs. Keep it on the backend and renew it before expiry.
POST /api/auth/custom-token
Content-Type: application/json
ClientToken: <member-sign-in-client-token>{
"grantType": "external_user",
"externalUserId": "<existing-member-id>"
}The token determines the tenant. Do not also send clientId, clientSecret or an
Authorization header. GOFA rechecks the originating secret's active status and
permission on every exchange; expiry, revocation or removal of that permission
also prevents further exchanges with already-issued ClientTokens.
GOFA creates the UID clientId|externalUserId and preserves existing member
records. New members are provisioned only when enabled for the tenant. Disabled
members cannot sign in. Use the matching Firebase project through the SDK's UAT
or production configuration.
Custom tokens expire after one hour; request them when needed and redeem them immediately. Firebase session renewal is separate from the backend ClientToken. See SDK authentication.
| Status | Meaning / handling |
|---|---|
| 400 | Invalid or mixed request fields; correct the request. |
| 401 | Invalid, expired, revoked or unauthorized credential/token. |
| 403 | Tenant sign-in or member access is disabled, or provisioning is unavailable. |
| 429 | Rate limit reached; honor Retry-After and use bounded backoff. |
| 503 | Provisioning/authentication unavailable; retry with bounded backoff. |
Keep credentials in a server secret store, exclude tokens/credentials from logs, and use HTTPS. During rotation, GOFA can enroll two active server secrets; deploy the replacement on your backend, verify it, then revoke the previous secret. Credential rotation does not terminate existing Firebase sessions.
Current limits are 60 validations per key per minute and 30 per key/source per minute for sign-in and token exchange separately. New-user provisioning is limited to 10 per key and 5 per key/source per minute. Coordinate expected concurrent sign-in volume with GOFA before rollout.