Token Store Management
Relevant source files
The following files were used as context for generating this wiki page:
Introduction
Token Store Management in the @cellarnode/auth package is responsible for the secure in-memory storage, retrieval, and automated lifecycle management of access tokens. It serves as a centralized hub that ensures the application always has a valid token for authenticated requests by handling proactive background refreshes and deduplicating concurrent refresh attempts.
The system is designed to be framework-agnostic, providing a clean interface for the AuthClient and AuthApi modules to interact with authentication state. By encapsulating token expiry logic and refresh buffer management, it prevents unauthorized request failures caused by expired credentials.
Sources: src/auth-store.ts:4-6, src/types.ts:60-66, README.md:1-5
Architecture and Components
The core of Token Store Management is the AuthStore interface, created via the createAuthStore factory function. The store maintains an internal state including the current access token, refresh timers, and pending refresh promises to handle concurrency.
Core State and Configuration
The store is configured with a base URL for the authentication server and timing parameters for refreshes.
| Parameter | Type | Default | Description |
|---|---|---|---|
baseUrl | string | N/A | The root URL for auth API endpoints. |
refreshPath | string | "/auth/refresh" | The endpoint used to obtain a new access token. |
refreshBuffer | number | 60 | Number of seconds before expiry to trigger a refresh. |
Sources: src/auth-store.ts:5-8, src/types.ts:54-58
Token Lifecycle Logic
The store implements a reactive lifecycle for tokens. When a token is set, the store calculates a delay based on the expiresIn value and the refreshBuffer to schedule the next update.
The diagram shows the recursive nature of the token refresh loop.
Sources: src/auth-store.ts:11-30, src/auth-store.ts:47-50
Token Refresh Mechanism
The refresh mechanism is designed to be "silent" and efficient. It uses the fetch API with credentials: "include" to ensure that HTTP-only refresh cookies are sent to the server during the POST request to the refresh endpoint.
Silent Refresh Process
- Trigger: Triggered either by a scheduled timer or a manual call to
ensureAccessToken(true). - Deduplication: If a refresh is already in progress, the store returns the existing
refreshPromiseinstead of starting a new network request. - Extraction: Uses a robust extraction utility to locate tokens in various response formats (e.g.,
accessToken,access_token, or nesteddataobjects). - Failure Handling: If the refresh request fails (non-OK response or network error), the store clears the current token and returns
null.
Sources: src/auth-store.ts:18-38, src/auth-store.ts:63-68, src/extract-token.ts:1-20
Refresh Concurrency
Concurrent requests for a token while one is being fetched are handled using a promise-locking pattern.
This sequence ensures only one network call is made even if multiple components request a fresh token simultaneously.
Sources: src/auth-store.ts:63-69, tests/auth-store.test.ts:70-85
Data Extraction and Normalization
The extractAccessToken utility provides compatibility with various backend response structures, ensuring the store can function with different API implementations.
| Logic Step | Target Field | Nested Paths |
|---|---|---|
| Primary | accessToken | Root level |
| Standard | access_token | Root level |
| Legacy | token | Root level |
| Nested Data | accessToken, access_token | payload.data.* |
| Session | accessToken, access_token | payload.session.* |
Sources: src/extract-token.ts:1-18
Integration with Auth Client
The AuthClient interacts with the AuthStore during every outgoing request. It retrieves the token via getAccessToken() and handles 401 Unauthorized responses by asking the store to ensureAccessToken(true).
The flow highlights the Store's role in the client's retry logic.
Sources: src/auth-client.ts:32-40, src/auth-client.ts:51-72
Summary of Store Interface
The AuthStore interface defines the following methods:
| Method | Description |
|---|---|
getAccessToken() | Returns the current token or null. |
hasAccessToken() | Returns true if a token is present. |
setAccessToken(token, expires) | Stores a new token and schedules a refresh. |
clearAccessToken() | Removes the token and cancels pending timers. |
ensureAccessToken(force) | Returns the current token or triggers a refresh if needed/forced. |
Sources: src/types.ts:60-66, src/auth-store.ts:41-72