@parcely/auth-token
Attach tokens to requests and optionally refresh on 401.
import { createAuthToken } from '@parcely/auth-token'
createAuthToken(options)
Creates an auth-token handler that can be installed on a client.
Options
| Option | Type | Default | Description |
|---|---|---|---|
scheme | string | 'Bearer' | The auth scheme prefix: 'Bearer', 'Basic', 'Token', or any custom string. Use '' for raw token. |
getToken | () => string | null | Promise<string | null> | (required) | Returns the current token. May be sync or async. When null, the header is not set (unauthenticated request passes through). |
header | string | 'Authorization' | The header name to set. Can be 'X-API-Key' or any custom header. |
refreshOn | number[] | [401] | HTTP status codes that trigger a token refresh. Only relevant when refresh is provided. |
refresh | () => Promise<string> | undefined | Async function that refreshes the token and returns the new token. When omitted, errors matching refreshOn propagate as-is. |
Return value
{
request: (config: RequestConfig) => RequestConfig | Promise<RequestConfig>
response: {
fulfilled?: (res: HttpResponse<unknown>) => HttpResponse<unknown> | Promise<HttpResponse<unknown>>
rejected?: (err: unknown) => unknown
}
install(client: Client): void
}
| Property | Description |
|---|---|
request | A request interceptor fulfilled handler that attaches the token. Skips when _retry: true is set on the config (preserves freshly-refreshed tokens). |
response | An object with optional fulfilled and rejected handlers for refresh logic. rejected intercepts errors matching refreshOn statuses. |
install(client) | Convenience method that wires both request and response interceptors onto the client. Required for refresh-then-retry to work (captures the client reference internally). |
Key behaviour
- Single-flight refresh: When multiple requests receive a 401 concurrently, only one refresh call is made. All waiting requests share the same refresh promise.
- Retry once: After a successful refresh, the original failed request is retried once with the new token.
- Bounded retry: If the retried request also returns a refresh-triggering status, it is not retried again (prevents infinite loops).
- Refresh failure: If the refresh call itself fails, the original error propagates to the caller.
Example
import { createClient } from '@parcely/core'
import { createAuthToken } from '@parcely/auth-token'
const http = createClient({ baseURL: 'https://api.example.com' })
const refreshClient = createClient({ baseURL: 'https://api.example.com' })
const auth = createAuthToken({
scheme: 'Bearer',
getToken: async () => localStorage.getItem('access_token'),
header: 'Authorization',
refreshOn: [401],
refresh: async () => {
const r = await refreshClient.post('/auth/refresh')
localStorage.setItem('access_token', r.data.access)
return r.data.access
},
})
auth.install(http)
Manual installation
http.interceptors.request.use(auth.request)
http.interceptors.response.use(auth.response.fulfilled, auth.response.rejected)