Architecture Overview
Relevant source files
The following files were used as context for generating this wiki page:
The @cellarnode/auth library provides a shared authentication infrastructure for CellarNode dashboards. It encompasses a framework-agnostic core for token management and API communication, alongside a suite of React UI components designed for One-Time Password (OTP) based authentication flows.
The architecture is built on three primary pillars: a stateful AuthStore for token persistence and automatic background refreshing, an AuthClient for authenticated HTTP requests with automatic retry logic, and an AuthApi that abstracts specific authentication endpoints.
Sources: package.json:3-5, README.md:3-5
Core System Components
The system is organized into decoupled modules that interact to manage the lifecycle of a user session.
AuthStore
The AuthStore is responsible for holding the accessToken in memory and managing its expiration. It implements a proactive refresh mechanism that triggers before the token expires based on a configurable refreshBuffer.
- Key Logic: Uses
setTimeoutto schedule aperformRefreshcall. - Concurrency: Deduplicates concurrent refresh requests using a shared promise (
refreshPromise) to prevent redundant network calls.
Sources: src/auth-store.ts:6-66, src/types.ts:58-64
AuthClient
The AuthClient is a wrapper around the browser fetch API. It automatically injects the Authorization: Bearer <token> header into outgoing requests unless explicitly instructed to skip authentication.
- Automatic Retry: If a request returns a
401 Unauthorizedstatus, the client attempts to refresh the token via the store and retries the request exactly once before failing. - Error Handling: Converts failed HTTP responses into structured
AuthErrorobjects containing machine-readable error codes and remaining OTP attempts.
Sources: src/auth-client.ts:6-79, src/types.ts:71-73
AuthApi
The AuthApi provides high-level methods for authentication actions such as registration, OTP requesting, and verification. It utilizes the extractAccessToken utility to handle various JSON response shapes from the backend.
Sources: src/auth-api.ts:14-80, src/extract-token.ts:1-21
Data Flow and Interaction
The following diagram illustrates the interaction between a React component, the API abstraction, the client, and the store during a standard verification flow.
Component Hierarchy
The library exposes both core logic and React UI components. The React components depend on the core instances (authApi and authStore) being passed in via props, allowing for flexible dependency injection.
| Component | Responsibility | Relevant Files |
|---|---|---|
| AuthStore | Token lifecycle and background refresh timers. | src/auth-store.ts |
| AuthClient | Header injection, 401 retries, and error parsing. | src/auth-client.ts |
| AuthApi | Endpoint definitions (register, login, logout, me). | src/auth-api.ts |
| LoginForm | Two-step UI (Email -> OTP) with countdowns and error handling. | src/react/login-form.tsx |
| RegisterForm | User registration UI for specific UserTypes. | src/react/register-form.tsx |
| Unauthorized | Portal-aware access denied views with redirection logic. | src/react/unauthorized.tsx |
Sources: src/index.ts:1-12, src/react/index.ts:3-20
Data Models
The system uses a strict set of TypeScript interfaces to ensure consistency between the API responses and the UI state.
AuthUser
Represents the authenticated user entity.
export interface AuthUser {
id: string;
email: string;
name: string;
userType: "importer" | "producer" | "admin";
orgId: string | null;
roles: string[];
createdAt: string;
}
Sources: src/types.ts:1-10
AuthError Logic
Errors are standardized through the AuthError class, which captures the HTTP status, a string-based error code (e.g., OTP_INVALID), and optional metadata like remainingAttempts.
| Code | Description |
|---|---|
USER_NOT_FOUND | No account matches the provided email. |
OTP_RATE_LIMIT | Requesting codes too frequently. |
OTP_MAX_ATTEMPTS | Too many failed verification attempts. |
USER_TYPE_MISMATCH | User is authorized but doesn't have the required userType for the portal. |
Sources: src/types.ts:35-46, src/react/login-form.tsx:55-61
Summary
The architecture of @cellarnode/auth prioritizes a separation of concerns between state management (AuthStore), network resilience (AuthClient), and presentation (React Components). By centralizing token refresh and retry logic in the core modules, the React UI remains focused on user interaction and workflow orchestration.
Sources: README.md:7-25, src/index.ts:1-24