# Auth — `client.auth` `AuthService` (source: `src/auth/AuthService.ts`). Player authentication: device ID login (primary for game clients), custom webhook login, logout, and auth state observation. ## Methods ```ts loginWithDevice(options?: LoginWithDeviceOptions): Promise loginWithCustom(options: LoginWithCustomOptions): Promise logout(): void get isAuthenticated(): boolean onAuthStateChange(listener: AuthStateListener): () => void ``` ### `LoginWithDeviceOptions` ```ts { region?: string; // default 'global' language?: string; // default 'en' nickname?: string; // omitted from the request when not set } ``` The device ID is auto-generated on first call and persisted in localStorage (`src/device/DeviceId.ts`). The request also carries the client's `projectKey`. ### `LoginWithCustomOptions` ```ts { customData: Record; // required — forwarded to the project's custom auth webhook region?: string; // default 'global' language?: string; // default 'en' nickname?: string; } ``` ### Login responses ```ts interface LoginViaDeviceResponse { accessToken?: string; refreshToken?: string } interface LoginViaCustomResponse { accessToken?: string; refreshToken?: string } ``` On success both tokens are saved to the client's `TokenStore`, the runtime starts (domains warmed, scenario engine restored, `player_login` event fired), and the state flips to `'signed-in'`. ## Auth state ```ts type AuthState = 'signed-in' | 'signed-out'; type AuthStateListener = (state: AuthState) => void; ``` - `isAuthenticated` is `true` while an access token is present in the token store. - `onAuthStateChange` fires the listener **immediately** with the current state and returns an unsubscribe function. - `logout()` clears tokens, stops the runtime (sync poll, scenario runs, cached domain data), and emits `'signed-out'`. ## Token refresh (automatic, transport level) Source: `src/transport/request.ts`. - Every request injects `Authorization: Bearer ` when a token exists. - On 401 the transport does a single-flight refresh against `POST /sdk/v1/authorization/refresh` (concurrent 401s share one refresh) and retries the original request once. - If refresh fails, tokens are cleared, `onAuthStateChange` listeners get `'signed-out'`, and the request throws `RudderAuthError`. ## TokenStore ```ts interface TokenStore { getAccessToken(): string | null; getRefreshToken(): string | null; saveTokens(accessToken: string, refreshToken: string): void; clear(): void; } ``` Factories (exported from the package root): - `createDefaultTokenStore()` — localStorage, with a silent in-memory fallback where localStorage is unavailable (SSR, private mode). This is the default when `tokenStore` is omitted from `RudderClientOptions`. - `createLocalStorageTokenStore()` — keys `rudder_access_token` / `rudder_refresh_token`. Provide a custom `TokenStore` via `RudderClientOptions.tokenStore` for other backends (sessionStorage, cookies). ## Errors - Constructor: missing `baseUrl`/`projectKey` → `RudderError`, `code: 'sdk/invalid-options'`. - Login failure → `RudderHttpError` (e.g. unknown project key) or `RudderNetworkError`. - Any later request with an expired session → `RudderAuthError` (after the refresh attempt above fails).