170 lines
5.9 KiB
Markdown
170 lines
5.9 KiB
Markdown
# 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
|
|
|
|
```ts
|
|
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`
|
|
|
|
```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`.
|
|
|
|
### `LoginWithGoogleOptions` / `LoginWithAppleOptions`
|
|
|
|
```ts
|
|
{
|
|
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`
|
|
|
|
```ts
|
|
{
|
|
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
|
|
|
|
```ts
|
|
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).
|
|
|
|
```ts
|
|
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`
|
|
|
|
```ts
|
|
{
|
|
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
|
|
|
|
```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 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
|
|
|
|
```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
|
|
|
|
- `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).
|