The endpoint
fetch interceptor
- Single-flight refresh. If 20 in-flight requests all trigger
ensureFresh()simultaneously, only one POST to/auth/refresh_tokenruns; the others await the same promise. - No 401 retry. A 401 after a fresh token means the session is dead — clear it and force re-auth. Retrying would mask real auth problems.
- Proactive threshold. 5 minutes is the reference webapp’s threshold. Shorter (1 min) makes more 401s likely on slow networks; longer (>10 min) wastes refresh calls.
axios interceptor
Server-side variant
Server-to-server integrations should:- Sign in once at boot (or on first call) and cache the session in memory.
- Run a background refresh timer (e.g.
setInterval(refresh, 55 * 60 * 1000)). - Persist the refresh token in a secret store, not in the access-token cache.
MFA-enabled accounts
If your service account has MFA enabled, the/auth response will come
back with Challenge instead of AccessToken. For service accounts,
turn MFA off at provisioning time and rely on a strong password +
network controls.
For interactive (user-driven) flows, complete the MFA challenge at
PUT /auth/challenge/mfa-token — see Authentication.
Common mistakes
Refreshing on 401 instead of proactively
Refreshing on 401 instead of proactively
The user’s request has already failed by then. Their UI shows the
error. Refresh ahead of time.
Not single-flighting the refresh
Not single-flighting the refresh
Without a shared
refreshPromise, multiple in-flight requests will
each trigger their own refresh. Best case: wasted calls. Worst case:
you race on saving the new token and lose one.Forgetting `X-Preferred-Partner-Id`
Forgetting `X-Preferred-Partner-Id`
Easy to do in the refresh interceptor — the refresh call itself doesn’t
need it, but every subsequent request does. Make sure
ensureFresh returns both pieces, and you set them together.Storing the refresh token in localStorage in a browser
Storing the refresh token in localStorage in a browser
The refresh token is long-lived. Put it behind a proxy on your backend,
or use an
HttpOnly cookie. The access token in localStorage is
survivable; the refresh token isn’t.