Files
edmand46 7271874cac
CI / check (push) Successful in 16s
CI / publish (push) Has been skipped
2.0.0: changelog and skill docs for slugs and environments
Claude-Session: https://claude.ai/code/session_01SMCvdwDmuxoaqGgvGBLk1V
2026-09-06 22:39:03 +03:00

4.0 KiB

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

loginWithDevice(options?: LoginWithDeviceOptions): Promise<LoginViaDeviceResponse>
loginWithCustom(options: LoginWithCustomOptions): Promise<LoginViaCustomResponse>
logout(): void
get isAuthenticated(): boolean
onAuthStateChange(listener: AuthStateListener): () => void

LoginWithDeviceOptions

{
  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

{
  customData: Record<string, unknown>;  // required — forwarded to the project's custom auth webhook
  region?: string;                      // default 'global'
  language?: string;                    // default 'en'
  nickname?: string;
}

Login responses

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'.

Environments

A project has two environments, staging and prod. The SDK key you pass as RudderClientOptions.projectKey belongs to one of them, so the environment is resolved at login and carried inside the access and refresh tokens; nothing in the client API takes an environment argument, and a player created in one environment is invisible in the other. Content released only to staging is empty for a prod key and vice versa.

Tokens issued before SDK 2.0.0 carry no environment claim and are rejected with 401. The transport's refresh then fails, clears the token store and emits 'signed-out' — log the player in again.

Auth state

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 <accessToken> 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

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/projectKeyRudderError, 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).