The two headers you always send
| Header | Required? | What it is | |
|---|---|---|---|
Authorization | Always | Cognito AccessToken returned from /auth. Refresh ~5 min before ExpiresIn. | |
X-Preferred-Partner-Id | Always when the user belongs to >1 partner; safest to always send | The partner the request applies to. Must be one of the user’s cognito:groups matching `/(partner-id-.+ | fd\d+)/`. The backend scopes all reads/writes by this. |
transformRequest
(see webapp/src/api/_init.js). Mirror this in your client.
1. Sign in
AccessToken
and the value of Challenge:
- Success (no MFA)
- MFA challenge
- Force new password
tokenExpirationDate = now() + ExpiresIn (seconds).Decoding the IdToken
TheIdToken is a standard JWT. Decode it client-side (e.g. with
jwt-decode) to read user claims:
account-disabled— the account is suspended.external-user— not allowed to log into a first-party app.
fd-admin, back-office-admin, webapp-access-group-<N>.
2. Make authenticated requests
3. Multi-factor authentication
MFA is mandatory for end-user logins after 2025-05-12.Respond to a challenge
DeviceKey and DeviceGroupKey if remember_device: true was set. Cache
them per-user — passing them on the next /auth call lets the user skip
the MFA prompt on a trusted device.
Configure MFA (post-login)
| Endpoint | Purpose |
|---|---|
GET /auth/mfa/settings | Current MFA state for the user |
PUT /auth/mfa/settings | Enable / disable / set preferred MFA method |
GET /auth/mfa/configure/totp | Get qr_uri + qr_secret for authenticator-app enrolment |
PUT /auth/mfa/configure/totp | Verify the TOTP setup with a mfa_token |
4. Refresh tokens
Access tokens expire after one hour. Refresh proactively when less than 5 minutes remain, not on the failed 401:The refresh token does not rotate. Keep using the original
RefreshToken
from the initial /auth call until the user signs out or it eventually
expires (Cognito default: 30 days).5. Forgot / reset password
6. Create users under a partner
If you’re letting partner-admins onboard users:POST /auth/partners/users/confirm ({email, conf_code}).
7. Logout
There is no server-side token revocation. Tokens remain valid until their natural expiry. To log a user out:- Drop the access token, ID token, and refresh token from your client store.
- Clear any
DeviceKey/DeviceGroupKeyyou cached for “remember device”.
8. Permissions and features
After login, fetch two things to drive your UI:permissions for “can this user open the campaign editor?” decisions
and features for “is the Wave package builder enabled for this partner?”
toggles.
9. Error model
| Status | Meaning | What to do |
|---|---|---|
401 | Missing/expired token, or admin marker tripped (account-disabled). | Re-authenticate. The reference webapp force-logs-out on any 401. |
403 | Authenticated but not authorised for this partner/resource. | Check X-Preferred-Partner-Id matches a group the token actually has. |
400 | Validation. | Inspect validation_errors[] in the response body. |
429 | Rate limit. | Back off — see Rate limits. |
message is an i18n key (always starts with error.); map it to your
own copy. Log error_code and the x-request-id response header in any
support ticket.
Security checklist
Never ship long-lived tokens to a browser
Never ship long-lived tokens to a browser
Access tokens are short-lived (~1h) and acceptable in a browser. The
refresh token is long-lived — keep it on your backend if your UI is
web-based, or use a secure storage API on native.
Always send X-Preferred-Partner-Id
Always send X-Preferred-Partner-Id
Even if your user belongs to only one partner. Omitting it on
multi-partner accounts will scope your call to an arbitrary partner.
Refresh proactively
Refresh proactively
Track
ExpiresIn and refresh when less than 5 minutes remain. Don’t refresh on
401 — your user request has already failed by then.Don't put tokens in URLs
Don't put tokens in URLs
Always the
Authorization header. URLs end up in access logs and
browser history.Pin staging vs production
Pin staging vs production
Use distinct credentials per environment in your CI/CD secrets.
Production credentials must never appear in staging logs.