Skip to main content

@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

OptionTypeDefaultDescription
schemestring'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).
headerstring'Authorization'The header name to set. Can be 'X-API-Key' or any custom header.
refreshOnnumber[][401]HTTP status codes that trigger a token refresh. Only relevant when refresh is provided.
refresh() => Promise<string>undefinedAsync 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
}
PropertyDescription
requestA request interceptor fulfilled handler that attaches the token. Skips when _retry: true is set on the config (preserves freshly-refreshed tokens).
responseAn 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)

See also