Authentication Adapters
The @archibald/auth package uses an adapter pattern on the client side: the SessionClient delegates every auth operation (login, logout, refresh, user loading, login check) to an AuthAdapter. The adapter decides how to talk to the BFF's auth endpoints and where tokens live.
Built-in adapters
CookieAuthAdapter (web, default)
The default adapter when none is configured. Tokens live in secure, httpOnly cookies (nct/ncr) set by the server — the client never sees them. Supports both login protocols via the credentials union CombinedCookieAuthCredentials:
authProtocol: 'password'(default when omitted) →POST auth/loginwith the credentials as body.authProtocol: 'oidc'→ full-page redirect toGET auth/login, forwarding only the query params allowed by theSessionClient'soidcConfig.queryParamsWhitelist. See OIDC Login Flow.
import { SessionClient, CookieAuthAdapter, type OidcConfig } from '@archibald/auth';
const oidcConfig: OidcConfig = { queryParamsWhitelist: ['returnPath'] };
const sessionClient = new SessionClient({ adapter: CookieAuthAdapter, api, oidcConfig });
HeaderAuthAdapter
For clients that manage tokens themselves (header strategy): tokens are returned in the response body, persisted via the client's storage adapter, and sent as Authorization: Bearer <token>. Password protocol only; on a failed refresh it logs the client out.
import { SessionClient, HeaderAuthAdapter } from '@archibald/auth';
const sessionClient = new SessionClient({ adapter: HeaderAuthAdapter, storage: 'local', api });
NativeAuthAdapter (React Native / Expo)
Exported from the expo entry point only (@archibald/auth), since it depends on expo-auth-session. Runs the OIDC authorization code flow in an in-app browser and exchanges the code via POST auth/token; falls back to header-style password login for non-OIDC credentials. Pair it with a secure-store-backed storage adapter — see the OIDC setup guide.
MockAdapter
For unit tests. Accepts any non-empty username/password and returns a static token/user ({ token: 'TOKEN', refresh: 'REFRESH', user: { id: 'id' } }).
import { SessionClient, MockAdapter } from '@archibald/auth';
const sessionClient = new SessionClient({ adapter: MockAdapter, api });
Writing a custom adapter
Extend the abstract AuthAdapter<User, Credentials> and override the operation hooks. The constructor receives the owning SessionClient, the api instance (exposed as this.createRequest), and the optional OidcConfig.
import { AuthAdapter, type AuthResponse, type AuthCheckResponse } from '@archibald/auth';
class CustomAdapter<User extends DefaultUser> extends AuthAdapter<User, MyCredentials> {
/** Called by sessionClient.logIn() (useLogin hook). */
override async onLogIn(credentials?: MyCredentials): Promise<AuthResponse<User>> { ... }
/** Called by sessionClient.logOut() (useLogOut hook). */
override async onLogOut(): Promise<AuthResponse<User>> { ... }
/** Called by sessionClient.refresh(). */
override async onRefresh(): Promise<AuthResponse<User>> { ... }
/** Called when user data is requested (useUser hook). */
override async onGetUser(): Promise<User> { ... }
/** Logged-in check without loading user data (sessionClient.check()). */
override async onCheckLoggedIn(): Promise<AuthCheckResponse> { ... }
}
const sessionClient = new SessionClient({ adapter: CustomAdapter, api });
Every base method throws Method not implemented. — only override what your strategy needs, but the SessionClient will call all five during a normal session lifecycle.
Storage adapters
Independently of the auth adapter, the SessionClient has a storage option (StorageAdapter subclass, or the shorthands 'cookie' — the default — and 'local') used by header-style adapters to persist tokens:
CookieStorageAdapter— non-httpOnly cookies (default).LocalStorageAdapter—localStorage.- Custom — e.g. the shop template's app platform wraps
expo-secure-storein aStorageAdapter<string>subclass.
The CookieAuthAdapter doesn't need storage for tokens (the server owns them), but SessionClient.loggedIn still consults storage.get('token').