Auth Client
Relevant source files
The following files were used as context for generating this wiki page:
The Auth Client is a core module within the @cellarnode/auth package designed to handle authenticated network requests. It serves as a wrapper around the native fetch API, providing automatic Bearer token injection, centralized error handling, and a retry mechanism for expired sessions.
The client operates in conjunction with an AuthStore to manage token persistence and an AuthApi to execute specific authentication flows like OTP verification and user registration. Its primary goal is to abstract the complexities of JWT (JSON Web Token) management and session refreshing from the application logic.
Sources: src/auth-client.ts:1-74, README.md:1-20
Architecture and Components
The Auth Client is initialized via the createAuthClient factory function. It relies on a configuration object that defines the communication parameters and state management dependencies.
Key Components
| Component | Description | Source |
|---|---|---|
AuthClient | The main interface exposing a fetch method for making authenticated requests. | src/types.ts:71-73 |
AuthStore | An interface used by the client to retrieve, set, and refresh access tokens. | src/types.ts:59-65 |
AuthError | A custom error class used to propagate HTTP status codes and specific auth failure codes. | src/types.ts:33-44 |
Data Flow for Authenticated Requests
The following diagram illustrates the internal logic of the fetch method, including token injection and the automatic 401 retry flow.
Core Functionality
1. Token Injection
Unless the skipAuth option is explicitly set to true, the client attempts to retrieve an access token from the provided AuthStore. If found, it adds an Authorization: Bearer <token> header to the outgoing request.
Sources: src/auth-client.ts:38-43, tests/auth-client.test.ts:25-42
2. Automatic Refresh Mechanism
When a request returns a 401 Unauthorized status, the client attempts a single recovery cycle:
- It calls
store.ensureAccessToken(true)to trigger a token refresh via the server's refresh endpoint. - If a new token is obtained, the original request is retried with the updated header.
- If the refresh fails or the retry also returns an error, the client clears the token store and triggers the optional
onAuthFailurecallback.
Sources: src/auth-client.ts:57-73, src/auth-store.ts:60-66
3. Error Handling
The client uses parseErrorResponse to extract structured error details from the server response. This includes an error message, a machine-readable code, and optional metadata like remainingAttempts (relevant for OTP verification).
// Example of the AuthError structure used by the client
export class AuthError extends Error {
constructor(
public readonly status: number,
public readonly code: string,
message: string,
public readonly remainingAttempts?: number,
) {
super(message);
this.name = "AuthError";
}
}
Sources: src/auth-client.ts:8-27, src/types.ts:33-44
Configuration Options
The AuthClientConfig defines the behavior of the client during initialization.
| Property | Type | Required | Description |
|---|---|---|---|
baseUrl | string | Yes | The root URL for all API requests. |
store | AuthStore | Yes | Implementation for token persistence and refreshing. |
onAuthFailure | () => void | No | Callback triggered when a session cannot be restored (e.g., redirect to login). |
Sources: src/auth-client.ts:6-7, src/types.ts:67-71
API Request Methods
The client is typically utilized by the AuthApi to provide high-level methods for authentication tasks.
AuthApi Methods Overview
- register: Sends user details to
/auth/register. - requestOtp: Requests a code via
/auth/request-otp. - verifyOtp: Exchanges a code for a token and updates the
AuthStore. - getMe: Fetches current user profile from
/auth/me. - logout: Notifies the server via
/auth/logout.
Sources: src/auth-api.ts:16-83, src/types.ts:75-81
Summary
The Auth Client provides a robust foundation for handling CellarNode authentication. By centralizing token management, 401 retries, and error parsing, it ensures consistent behavior across various dashboards and UI components while maintaining a clean, framework-agnostic interface.