Files
rudder-js-sdk/skills/rudder-web-sdk/reference/auth.md
T
edmand46 aa9d9800c9
CI / check (push) Successful in 15s
CI / publish (push) Has been skipped
docs: README, CHANGELOG and skill for @rudder/sdk 0.1.0 with generated module clients
2026-09-17 15:28:08 +03:00

5.9 KiB

Auth — client.auth

AuthService (source: src/auth/AuthService.ts). Player authentication: device ID login (primary for game clients), Google / Apple sign-in, custom webhook login, identity linking/unlinking, logout, and auth state observation.

Methods

loginWithDevice(options?: LoginWithDeviceOptions): Promise<LoginViaDeviceResponse>
loginWithGoogle(options: LoginWithGoogleOptions): Promise<LoginViaGoogleResponse>
loginWithApple(options: LoginWithAppleOptions): Promise<LoginViaAppleResponse>
loginWithCustom(options: LoginWithCustomOptions): Promise<LoginViaCustomResponse>
linkWithGoogle(idToken: string): Promise<void>
linkWithApple(idToken: string): Promise<void>
linkWithCustom(options: LinkWithCustomOptions): Promise<void>
unlinkIdentity(provider: string): Promise<void>
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.

LoginWithGoogleOptions / LoginWithAppleOptions

{
  idToken: string;    // required — Google ID token / Apple identity token
  region?: string;    // default 'global'
  language?: string;  // default 'en'
  nickname?: string;  // omitted from the request when not set
}

The client obtains the idToken from the provider's own sign-in flow (Google Identity Services, Sign in with Apple) and forwards it to POST /sdk/v1/authorization/google or /sdk/v1/authorization/apple.

LoginWithCustomOptions

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

Login responses

interface LoginViaDeviceResponse { accessToken?: string; refreshToken?: string }
interface LoginViaGoogleResponse { accessToken?: string; refreshToken?: string }
interface LoginViaAppleResponse { accessToken?: string; refreshToken?: string }
interface LoginViaCustomResponse { accessToken?: string; refreshToken?: string }

On success both tokens are saved to the client's TokenStore, player and catalog are warmed, the revision poll starts, and the state flips to 'signed-in'.

Identity linking

linkWithGoogle / linkWithApple / linkWithCustom attach an additional identity to the currently signed-in player; unlinkIdentity detaches one. All four require an active session — the access token is sent automatically (transport level). They return nothing (HTTP 204).

await client.auth.linkWithGoogle(idToken);
await client.auth.linkWithApple(idToken);
await client.auth.linkWithCustom({ customData, provider }); // provider optional
await client.auth.unlinkIdentity('custom:my-backend');

LinkWithCustomOptions

{
  customData: Record<string, unknown>;  // required
  provider?: string;                    // custom provider name; omitted = the default provider
}

unlinkIdentity(provider) takes the full provider string: device, google, apple, custom, or custom:<name>.

Linked identities appear on the player profile: client.player.value.identities: PlayerProfileIdentity[] with { provider: string; subject: string; createdAt: string }.

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.

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 revision poll, drops 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

  • createClient: missing 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).