@voltro/plugin-auth-social 0.85.0 → 0.87.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5987 -0
- package/README.md +8 -1
- package/THIRD-PARTY-NOTICES.md +1122 -31
- package/dist/apple.js +64 -0
- package/dist/callback.js +129 -0
- package/dist/discord.js +38 -0
- package/dist/epic.js +39 -0
- package/dist/errors.js +34 -0
- package/dist/github.js +37 -0
- package/dist/guestHandoff.js +61 -0
- package/dist/guestUpgrade.js +97 -0
- package/dist/identityStore.js +124 -0
- package/dist/index.d.ts +292 -16
- package/dist/index.js +16 -721
- package/dist/linking.js +23 -0
- package/dist/login.js +32 -0
- package/dist/nativeGuestUpgrade.js +66 -0
- package/dist/pkce.js +5 -0
- package/dist/platform.js +115 -0
- package/dist/plugin.js +741 -0
- package/dist/providers.js +130 -0
- package/dist/signIn.js +84 -0
- package/dist/steam.js +152 -0
- package/dist/web/guestUpgradeClient.js +109 -0
- package/dist/web.d.ts +54 -0
- package/dist/web.js +1 -0
- package/package.json +11 -5
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
import { AuthConfig } from '@voltro/plugin-auth';
|
|
2
|
+
import { DataStore } from '@voltro/database';
|
|
2
3
|
import { Effect } from 'effect';
|
|
4
|
+
import { GuestAuthOptions } from '@voltro/plugin-auth';
|
|
5
|
+
import { GuestAuthService } from '@voltro/plugin-auth';
|
|
6
|
+
import { HotStoreShape } from '@voltro/kv/hot';
|
|
7
|
+
import { PluginEnvVar } from '@voltro/protocol';
|
|
8
|
+
import { PluginPermission } from '@voltro/protocol';
|
|
3
9
|
import { Predicate } from '@voltro/database';
|
|
4
10
|
import { Subject } from '@voltro/protocol';
|
|
5
11
|
import { TableLike } from '@voltro/database';
|
|
6
12
|
import { UserStore } from '@voltro/plugin-auth';
|
|
13
|
+
import { VoidIfEmpty } from 'effect/Types';
|
|
7
14
|
import { VoltroPlugin } from '@voltro/protocol';
|
|
15
|
+
import { YieldableError } from 'effect/Cause';
|
|
8
16
|
|
|
9
17
|
/** Default lifetime we mint. Minutes, not months — see the header. */
|
|
10
18
|
export declare const APPLE_CLIENT_SECRET_DEFAULT_TTL_S = 900;
|
|
@@ -48,6 +56,13 @@ export declare interface AppleUserPayload {
|
|
|
48
56
|
readonly email: string | null;
|
|
49
57
|
}
|
|
50
58
|
|
|
59
|
+
/** Preserve the guest subject ID. Conflict with any existing local email or
|
|
60
|
+
* provider link refuses with merge-required; this function never merges or
|
|
61
|
+
* moves another account automatically. A provider account without an address
|
|
62
|
+
* (Steam, Epic, a console) registers the guest without one, never a synthetic
|
|
63
|
+
* address. */
|
|
64
|
+
export declare const completeGuestSocialUpgrade: (options: GuestSocialUpgradeOptions) => Effect.Effect<GuestSocialUpgradeResult>;
|
|
65
|
+
|
|
51
66
|
/**
|
|
52
67
|
* Resolve a verified social profile into a session, applying the account-link
|
|
53
68
|
* policy and the subject guards.
|
|
@@ -61,7 +76,7 @@ export declare const completeSocialSignIn: (o: SocialSignInOptions) => Effect.Ef
|
|
|
61
76
|
|
|
62
77
|
/** DataStore-backed store — the production choice. Bind it from the plugin's
|
|
63
78
|
* `bindDataStore` hook, or construct it yourself over `ctx.store`. */
|
|
64
|
-
export declare const dataStoreSocialIdentityStore: (store: SocialIdentityDataStore) => SocialIdentityStore;
|
|
79
|
+
export declare const dataStoreSocialIdentityStore: (store: SocialIdentityDataStore | Pick<DataStore, "query" | "insert" | "update" | "delete"> | Pick<DataStore, "query" | "insert" | "insertIgnoreWithOutcome" | "update" | "delete">) => SocialIdentityStore;
|
|
65
80
|
|
|
66
81
|
/**
|
|
67
82
|
* Decide what a verified social identity means for local accounts.
|
|
@@ -71,6 +86,68 @@ export declare const dataStoreSocialIdentityStore: (store: SocialIdentityDataSto
|
|
|
71
86
|
*/
|
|
72
87
|
export declare const decideSocialLink: (input: SocialLinkInput) => SocialLinkDecision;
|
|
73
88
|
|
|
89
|
+
/**
|
|
90
|
+
* A platform login for a platform Voltro does not ship: a console or store
|
|
91
|
+
* whose SDK issues a ticket your server can verify (often under NDA). `verify`
|
|
92
|
+
* receives the ticket exactly as the game sent it and returns the platform's
|
|
93
|
+
* stable account id, or throws {@link PlatformTicketError} when the platform
|
|
94
|
+
* refuses it.
|
|
95
|
+
*/
|
|
96
|
+
export declare const definePlatformLogin: (definition: PlatformLoginDefinition) => PlatformLogin;
|
|
97
|
+
|
|
98
|
+
/** The authenticated Discord user, without an access token or arbitrary API
|
|
99
|
+
* payload. Discord snowflakes remain strings; number coercion loses bits. */
|
|
100
|
+
export declare interface DiscordIdentity {
|
|
101
|
+
readonly accountId: string;
|
|
102
|
+
readonly login: string;
|
|
103
|
+
readonly name: string | null;
|
|
104
|
+
readonly avatarUrl: string | null;
|
|
105
|
+
readonly email: string | null;
|
|
106
|
+
readonly emailVerified: boolean;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Epic Online Services Connect: the game calls `EOS_Connect_CopyIdToken` after
|
|
111
|
+
* `EOS_Connect_Login` and sends the token; the server checks Epic's signature,
|
|
112
|
+
* issuer, client and deployment. The account id is the Product User ID, the one
|
|
113
|
+
* EOS keeps for a player across every account linked to it (Epic, Steam,
|
|
114
|
+
* consoles), so this login covers every platform EOS covers.
|
|
115
|
+
*/
|
|
116
|
+
export declare const eosPlatformLogin: (options?: EosPlatformLoginOptions) => PlatformLogin;
|
|
117
|
+
|
|
118
|
+
export declare interface EosPlatformLoginOptions {
|
|
119
|
+
/** EOS client id the game initializes the SDK with. Default: `VOLTRO_EOS_CLIENT_ID`. */
|
|
120
|
+
readonly clientId?: string;
|
|
121
|
+
/** EOS deployment id; tokens from any other deployment are refused. Default: `VOLTRO_EOS_DEPLOYMENT_ID`. */
|
|
122
|
+
readonly deploymentId?: string;
|
|
123
|
+
/** Test seam — a loopback JWKS. */
|
|
124
|
+
readonly jwksUrl?: string;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export declare interface EpicIdentity {
|
|
128
|
+
readonly accountId: string;
|
|
129
|
+
readonly login: string;
|
|
130
|
+
readonly name: null;
|
|
131
|
+
readonly avatarUrl: null;
|
|
132
|
+
readonly email: null;
|
|
133
|
+
readonly emailVerified: false;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export declare const fetchDiscordIdentity: (accessToken: string, options: {
|
|
137
|
+
readonly apiBase: string;
|
|
138
|
+
readonly fetchImpl?: typeof fetch;
|
|
139
|
+
}) => Promise<DiscordIdentity>;
|
|
140
|
+
|
|
141
|
+
/** Authenticate through Epic's documented v2 token introspection endpoint.
|
|
142
|
+
* Account ids are read only from the server response, never a client payload
|
|
143
|
+
* or an unverified access-token body. No provider email proof is available. */
|
|
144
|
+
export declare const fetchEpicIdentity: (accessToken: string, options: {
|
|
145
|
+
readonly apiBase: string;
|
|
146
|
+
readonly clientId: string;
|
|
147
|
+
readonly fetchImpl?: typeof fetch;
|
|
148
|
+
readonly now?: () => number;
|
|
149
|
+
}) => Promise<EpicIdentity>;
|
|
150
|
+
|
|
74
151
|
/**
|
|
75
152
|
* Resolve the authenticated GitHub user behind an access token.
|
|
76
153
|
*
|
|
@@ -95,6 +172,25 @@ export declare interface GithubIdentity {
|
|
|
95
172
|
readonly emailVerified: boolean;
|
|
96
173
|
}
|
|
97
174
|
|
|
175
|
+
export declare interface GuestSocialUpgradeOptions {
|
|
176
|
+
/** Verified server-side provider result, never a client-submitted profile. */
|
|
177
|
+
readonly profile: SocialProfile;
|
|
178
|
+
readonly credential: string;
|
|
179
|
+
readonly store: DataStore;
|
|
180
|
+
readonly guest: GuestAuthOptions;
|
|
181
|
+
/** The same complete lifecycle port installed by the guest plugin. */
|
|
182
|
+
readonly service?: GuestAuthService;
|
|
183
|
+
readonly users: UserStore;
|
|
184
|
+
readonly config: AuthConfig;
|
|
185
|
+
/** Required when ensureActor is installed: bind its write to this same
|
|
186
|
+
* transaction. There must be no independent pool/write during promotion. */
|
|
187
|
+
readonly configForTransaction?: (store: DataStore) => AuthConfig;
|
|
188
|
+
readonly ipAddress?: string | null;
|
|
189
|
+
readonly userAgent?: string | null;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
declare type GuestSocialUpgradeResult = SocialSignInOk | SocialSignInRefused;
|
|
193
|
+
|
|
98
194
|
/** Is this one of Apple's per-app relay addresses? Used as a fallback when the
|
|
99
195
|
* `is_private_email` claim is absent (older tokens omit it). */
|
|
100
196
|
export declare const isApplePrivateRelayEmail: (email: string | null) => boolean;
|
|
@@ -121,6 +217,12 @@ export declare const linkSocialIdentity: (store: SocialIdentityStore, userId: st
|
|
|
121
217
|
* this table means every user's social login unlinks. Not for production. */
|
|
122
218
|
export declare const memorySocialIdentityStore: (seed?: ReadonlyArray<SocialIdentityRecord>) => SocialIdentityStore;
|
|
123
219
|
|
|
220
|
+
declare interface NativeGuestUpgradeConfig {
|
|
221
|
+
/** Exact redirect URIs the app may name — a custom scheme (`acme://auth/upgrade`) or an
|
|
222
|
+
* https universal link. No wildcards. */
|
|
223
|
+
readonly redirectUris: ReadonlyArray<string>;
|
|
224
|
+
}
|
|
225
|
+
|
|
124
226
|
/**
|
|
125
227
|
* Parse Apple's `user` form field. Returns `null` for an absent or unparseable
|
|
126
228
|
* value — which is the NORMAL case on every authorization after the first, not
|
|
@@ -129,6 +231,42 @@ export declare const memorySocialIdentityStore: (seed?: ReadonlyArray<SocialIden
|
|
|
129
231
|
*/
|
|
130
232
|
export declare const parseAppleUserPayload: (raw: string | undefined | null) => AppleUserPayload | null;
|
|
131
233
|
|
|
234
|
+
/** The platform account a verified ticket proves. */
|
|
235
|
+
export declare interface PlatformAccount {
|
|
236
|
+
/** The platform's stable account id: a SteamID64, an EOS Product User ID, a
|
|
237
|
+
* console account id. This, never a name, is what the identity row is keyed by. */
|
|
238
|
+
readonly accountId: string;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/** One platform a game can sign in with. Build one with {@link steamPlatformLogin},
|
|
242
|
+
* {@link eosPlatformLogin} or {@link definePlatformLogin}. */
|
|
243
|
+
export declare interface PlatformLogin {
|
|
244
|
+
/** Route segment and identity namespace: `steam`, `eos`, `xbox`, … */
|
|
245
|
+
readonly id: string;
|
|
246
|
+
/** Verify a ticket with the platform. Throws {@link PlatformTicketError} for a
|
|
247
|
+
* ticket the platform refuses; any other failure answers 503. */
|
|
248
|
+
readonly verify: (ticket: string) => Promise<PlatformAccount>;
|
|
249
|
+
readonly declaredEnv: ReadonlyArray<PluginEnvVar>;
|
|
250
|
+
readonly permissions: ReadonlyArray<PluginPermission>;
|
|
251
|
+
/** Resolve every credential once; throws when one is missing. Runs at boot. */
|
|
252
|
+
readonly check: () => void;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
export declare interface PlatformLoginDefinition {
|
|
256
|
+
readonly id: string;
|
|
257
|
+
readonly verify: (ticket: string) => Promise<PlatformAccount>;
|
|
258
|
+
readonly declaredEnv?: ReadonlyArray<PluginEnvVar>;
|
|
259
|
+
readonly permissions?: ReadonlyArray<PluginPermission>;
|
|
260
|
+
readonly check?: () => void;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/** The platform refused a game client's sign-in ticket. One class for every
|
|
264
|
+
* reason, for the same reason as {@link SocialIdTokenError}: the caller must
|
|
265
|
+
* refuse the sign-in either way, and the `message` says which check failed. */
|
|
266
|
+
export declare class PlatformTicketError extends SocialAuthError {
|
|
267
|
+
constructor(message: string);
|
|
268
|
+
}
|
|
269
|
+
|
|
132
270
|
/** Test seam — drop the parsed-key and minted-secret caches. */
|
|
133
271
|
export declare const _resetAppleSecretCache: () => void;
|
|
134
272
|
|
|
@@ -183,8 +321,6 @@ export declare type SocialAuthErrorCode =
|
|
|
183
321
|
| 'id_token_invalid'
|
|
184
322
|
/** The ID token verified but its `nonce` was not the one we minted. */
|
|
185
323
|
| 'nonce_mismatch'
|
|
186
|
-
/** The provider identified the user but gave us no email to work with. */
|
|
187
|
-
| 'no_email'
|
|
188
324
|
/** An account with this email exists and the link policy refused to attach. */
|
|
189
325
|
| 'account_exists_unlinked'
|
|
190
326
|
/** Linking requires a provider-VERIFIED email and this one is not. */
|
|
@@ -192,14 +328,24 @@ export declare type SocialAuthErrorCode =
|
|
|
192
328
|
/** Linking refused because the address is a per-app Apple private relay. */
|
|
193
329
|
| 'private_relay_email'
|
|
194
330
|
/** A post-authentication subject guard vetoed the login. */
|
|
195
|
-
| 'guard_rejected'
|
|
331
|
+
| 'guard_rejected'
|
|
332
|
+
/** The platform refused a game client's sign-in ticket (forged, expired,
|
|
333
|
+
* another app or deployment). */
|
|
334
|
+
| 'ticket_rejected';
|
|
196
335
|
|
|
197
336
|
export declare const socialAuthPlugin: (options: SocialAuthPluginOptions) => VoltroPlugin;
|
|
198
337
|
|
|
199
338
|
export declare interface SocialAuthPluginOptions {
|
|
200
339
|
/** Which providers this app offers. A key with an empty object takes every
|
|
201
340
|
* credential from the environment. */
|
|
202
|
-
readonly providers
|
|
341
|
+
readonly providers?: Partial<Record<SocialProviderId, SocialProviderConfig>>;
|
|
342
|
+
/**
|
|
343
|
+
* Platforms a game client signs in with by ticket: `steamPlatformLogin()`,
|
|
344
|
+
* `eosPlatformLogin()`, or your own `definePlatformLogin(...)` for a console.
|
|
345
|
+
* Mounts `POST {prefix}/platform/{id}/sign-in`, and with `guestUpgrade` also
|
|
346
|
+
* `POST {prefix}/platform/{id}/link`. A platform account needs no email.
|
|
347
|
+
*/
|
|
348
|
+
readonly platforms?: ReadonlyArray<PlatformLogin>;
|
|
203
349
|
/** The same user store `authRoutesPlugin` runs on. */
|
|
204
350
|
readonly users: UserStore;
|
|
205
351
|
/**
|
|
@@ -238,6 +384,9 @@ export declare interface SocialAuthPluginOptions {
|
|
|
238
384
|
readonly stateCookieName?: string;
|
|
239
385
|
/** Disambiguates multiple instances of this plugin in one app. */
|
|
240
386
|
readonly name?: string;
|
|
387
|
+
/** Opt-in two-step browser promotion. Provider login only prepares a signed
|
|
388
|
+
* handoff; a CSRF-protected confirmation must prove the durable guest device. */
|
|
389
|
+
readonly guestUpgrade?: SocialGuestUpgradeConfig;
|
|
241
390
|
}
|
|
242
391
|
|
|
243
392
|
/** The tables this package contributes, as an array. */
|
|
@@ -320,7 +469,7 @@ export declare const socialCompleteLogin: (o: SocialCompleteLoginOptions) => Pro
|
|
|
320
469
|
export declare interface SocialCompleteLoginOptions {
|
|
321
470
|
readonly provider: SocialProviderId;
|
|
322
471
|
readonly clientId: string;
|
|
323
|
-
/**
|
|
472
|
+
/** OAuth client secret. Apple: omit and pass
|
|
324
473
|
* {@link SocialCompleteLoginOptions.appleKey} — its secret is a JWT we sign. */
|
|
325
474
|
readonly clientSecret?: string;
|
|
326
475
|
/** Apple only: the `.p8` key material a client secret is minted from. */
|
|
@@ -336,8 +485,8 @@ export declare interface SocialCompleteLoginOptions {
|
|
|
336
485
|
readonly expectedState: string;
|
|
337
486
|
/** The PKCE verifier `socialBeginLogin` minted. */
|
|
338
487
|
readonly codeVerifier: string;
|
|
339
|
-
/** The OIDC nonce `socialBeginLogin` minted. Required for
|
|
340
|
-
*
|
|
488
|
+
/** The OIDC nonce `socialBeginLogin` minted. Required for every OIDC
|
|
489
|
+
* provider; meaningless for providers that return no ID token. */
|
|
341
490
|
readonly expectedNonce?: string;
|
|
342
491
|
/** Apple only: the raw `user` form field. Present on the FIRST authorization
|
|
343
492
|
* and never again — see `apple.ts`. */
|
|
@@ -376,6 +525,18 @@ export declare class SocialExchangeError extends SocialAuthError {
|
|
|
376
525
|
constructor(code: SocialAuthErrorCode, message: string, status?: number);
|
|
377
526
|
}
|
|
378
527
|
|
|
528
|
+
export declare interface SocialGuestUpgradeConfig {
|
|
529
|
+
readonly guest: GuestAuthOptions;
|
|
530
|
+
/** Reuse the port installed by auth.guest; no automatic backend switch. */
|
|
531
|
+
readonly service?: (store: DataStore) => GuestAuthService;
|
|
532
|
+
/** Same-origin application page presenting explicit upgrade confirmation. */
|
|
533
|
+
readonly confirmationRedirect: string;
|
|
534
|
+
readonly configForTransaction?: (store: DataStore) => AuthConfig;
|
|
535
|
+
/** Opt-in promotion for cookie-less game clients through the system browser and a sealed,
|
|
536
|
+
* PKCE-bound one-time code. Absent mounts no `/upgrade/native/*` route. */
|
|
537
|
+
readonly native?: NativeGuestUpgradeConfig;
|
|
538
|
+
}
|
|
539
|
+
|
|
379
540
|
/**
|
|
380
541
|
* The social-identity table.
|
|
381
542
|
*
|
|
@@ -386,6 +547,17 @@ export declare class SocialExchangeError extends SocialAuthError {
|
|
|
386
547
|
*/
|
|
387
548
|
export declare const socialIdentitiesTable: TableLike;
|
|
388
549
|
|
|
550
|
+
/** The provider account already has an identity row: another login created it
|
|
551
|
+
* first (two first sign-ins of one Steam player racing). Read it and use it. */
|
|
552
|
+
export declare class SocialIdentityConflict extends SocialIdentityConflict_base<{
|
|
553
|
+
readonly provider: string;
|
|
554
|
+
}> {
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
declare const SocialIdentityConflict_base: new <A extends Record<string, any> = {}>(args: VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => YieldableError & {
|
|
558
|
+
readonly _tag: "SocialIdentityConflict";
|
|
559
|
+
} & Readonly<A>;
|
|
560
|
+
|
|
389
561
|
/** The slice of `DataStore` this store needs — narrow so a caller can pass a
|
|
390
562
|
* transactional view, a namespaced view, or a test double. */
|
|
391
563
|
export declare interface SocialIdentityDataStore {
|
|
@@ -399,6 +571,14 @@ export declare interface SocialIdentityDataStore {
|
|
|
399
571
|
}>;
|
|
400
572
|
}): Promise<ReadonlyArray<Readonly<Record<string, unknown>>>>;
|
|
401
573
|
insert(table: string, row: Readonly<Record<string, unknown>>): Promise<Readonly<Record<string, unknown>>>;
|
|
574
|
+
/** When present, the identity is recorded with it: the store decides atomically
|
|
575
|
+
* which of two concurrent first logins won, also where it enforces no unique. */
|
|
576
|
+
insertIgnoreWithOutcome?(table: string, row: Readonly<Record<string, unknown>>, options: {
|
|
577
|
+
readonly conflictColumns: ReadonlyArray<string>;
|
|
578
|
+
}): Promise<{
|
|
579
|
+
readonly row: Readonly<Record<string, unknown>>;
|
|
580
|
+
readonly outcome: 'inserted' | 'ignored';
|
|
581
|
+
}>;
|
|
402
582
|
update(table: string, primaryKey: string, patch: Readonly<Record<string, unknown>>): Promise<Readonly<Record<string, unknown>> | null>;
|
|
403
583
|
delete(table: string, primaryKey: string): Promise<boolean>;
|
|
404
584
|
}
|
|
@@ -412,6 +592,11 @@ export declare interface SocialIdentityInput {
|
|
|
412
592
|
readonly emailVerified: boolean;
|
|
413
593
|
}
|
|
414
594
|
|
|
595
|
+
/** Verified browser and native identities share the same account-link contract.
|
|
596
|
+
* Steam uses OpenID/tickets rather than an OAuth authorize-code descriptor; EOS
|
|
597
|
+
* is a platform login (`eosPlatformLogin`), keyed by the Product User ID. */
|
|
598
|
+
export declare type SocialIdentityProviderId = SocialProviderId | 'steam' | 'eos';
|
|
599
|
+
|
|
415
600
|
export declare interface SocialIdentityRecord {
|
|
416
601
|
readonly id: string;
|
|
417
602
|
readonly userId: string;
|
|
@@ -432,8 +617,9 @@ export declare interface SocialIdentityStore {
|
|
|
432
617
|
readonly findByProviderAccount: (provider: string, providerAccountId: string) => Effect.Effect<SocialIdentityRecord | null>;
|
|
433
618
|
/** Every provider a user has connected — the account-settings list. */
|
|
434
619
|
readonly listForUser: (userId: string) => Effect.Effect<ReadonlyArray<SocialIdentityRecord>>;
|
|
435
|
-
/** Create the link.
|
|
436
|
-
|
|
620
|
+
/** Create the link. Fails with {@link SocialIdentityConflict} when the provider
|
|
621
|
+
* account already has one — the unique `[provider, providerAccountId]`. */
|
|
622
|
+
readonly insert: (input: SocialIdentityInput) => Effect.Effect<SocialIdentityRecord, SocialIdentityConflict>;
|
|
437
623
|
/** Stamp `lastLoginAt` on a returning login. */
|
|
438
624
|
readonly touch: (identityId: string, at: Date) => Effect.Effect<void>;
|
|
439
625
|
/** Unlink a provider from a user. Returns whether a row was removed. */
|
|
@@ -459,7 +645,8 @@ export declare type SocialLinkDecision =
|
|
|
459
645
|
readonly kind: 'sign-in';
|
|
460
646
|
readonly userId: string;
|
|
461
647
|
}
|
|
462
|
-
/** No identity, no account with this email
|
|
648
|
+
/** No identity, and no account with this email (or no email at all) —
|
|
649
|
+
* provision a new user. */
|
|
463
650
|
| {
|
|
464
651
|
readonly kind: 'create-user';
|
|
465
652
|
}
|
|
@@ -520,14 +707,15 @@ export declare interface SocialLoginHandoff {
|
|
|
520
707
|
}
|
|
521
708
|
|
|
522
709
|
/**
|
|
523
|
-
* A verified identity, normalised across the
|
|
710
|
+
* A verified identity, normalised across the registered providers.
|
|
524
711
|
*
|
|
525
712
|
* `emailVerified` is the field every security decision downstream reads. It is
|
|
526
713
|
* the PROVIDER's assertion that it verified ownership of `email` — never our
|
|
527
714
|
* inference, and never `true` by default. See `linking.ts`.
|
|
528
715
|
*/
|
|
529
716
|
export declare interface SocialProfile {
|
|
530
|
-
|
|
717
|
+
/** A registered provider id, or the id of a platform login (`eos`, a console). */
|
|
718
|
+
readonly provider: SocialIdentityProviderId | (string & {});
|
|
531
719
|
/** The provider's stable, opaque id for this account — `sub` on Google and
|
|
532
720
|
* Apple, the numeric account id on GitHub. This, not the email, is what an
|
|
533
721
|
* identity row is keyed by: an email can change hands, this cannot. */
|
|
@@ -562,7 +750,7 @@ export declare const socialProvider: (id: string, overrides?: SocialEndpointOver
|
|
|
562
750
|
* value, because a default credential is a shipped secret. */
|
|
563
751
|
export declare interface SocialProviderConfig {
|
|
564
752
|
readonly clientId?: string;
|
|
565
|
-
/**
|
|
753
|
+
/** OAuth client secret. Apple uses {@link SocialProviderConfig.appleKey}. */
|
|
566
754
|
readonly clientSecret?: string;
|
|
567
755
|
/** Apple only: Team ID + Key ID + the `.p8` contents. */
|
|
568
756
|
readonly appleKey?: AppleClientSecretKey;
|
|
@@ -599,10 +787,10 @@ export declare interface SocialProviderDescriptor {
|
|
|
599
787
|
}
|
|
600
788
|
|
|
601
789
|
/** The providers this package ships. */
|
|
602
|
-
export declare type SocialProviderId = 'google' | 'github' | 'apple';
|
|
790
|
+
export declare type SocialProviderId = 'google' | 'github' | 'apple' | 'discord' | 'twitch' | 'microsoft' | 'epic';
|
|
603
791
|
|
|
604
792
|
/** How the provider hands the callback back to us. Apple POSTs (cross-site,
|
|
605
|
-
* `form_post`) whenever `name` / `email` scopes are requested; the
|
|
793
|
+
* `form_post`) whenever `name` / `email` scopes are requested; the others
|
|
606
794
|
* redirect with a query string. This changes the cookie the state must live
|
|
607
795
|
* in — see `plugin.ts`. */
|
|
608
796
|
export declare type SocialResponseMode = 'query' | 'form_post';
|
|
@@ -614,6 +802,12 @@ export declare interface SocialSignInOk {
|
|
|
614
802
|
readonly subject: Subject;
|
|
615
803
|
/** Attach this to the response. */
|
|
616
804
|
readonly setCookie: string;
|
|
805
|
+
/** The same session for a client that presents it in the session header
|
|
806
|
+
* instead of a cookie (a game). `expiresAt` is in Unix seconds. */
|
|
807
|
+
readonly session: {
|
|
808
|
+
readonly value: string;
|
|
809
|
+
readonly expiresAt: number;
|
|
810
|
+
};
|
|
617
811
|
/** A new local user was provisioned by this login. */
|
|
618
812
|
readonly created: boolean;
|
|
619
813
|
/** The identity was attached to a PRE-EXISTING account by policy. */
|
|
@@ -663,4 +857,86 @@ export declare class SocialStateMismatchError extends SocialAuthError {
|
|
|
663
857
|
constructor(message: string);
|
|
664
858
|
}
|
|
665
859
|
|
|
860
|
+
/** Steam OpenID 2.0 does not use OAuth PKCE. State is server minted and bound
|
|
861
|
+
* into the exact return_to which Steam signs. Persist this handoff securely. */
|
|
862
|
+
export declare const steamBeginOpenId: (options: {
|
|
863
|
+
readonly returnTo: string;
|
|
864
|
+
readonly realm?: string;
|
|
865
|
+
}) => SteamOpenIdHandoff;
|
|
866
|
+
|
|
867
|
+
/** Direct OP verification plus local atomic replay admission. Unavailable hot
|
|
868
|
+
* state refuses; memory ports are explicitly refused for a multi-node owner. */
|
|
869
|
+
export declare const steamCompleteOpenId: (options: SteamCompleteOpenIdOptions) => Effect.Effect<SocialProfile, SocialAuthError>;
|
|
870
|
+
|
|
871
|
+
export declare interface SteamCompleteOpenIdOptions {
|
|
872
|
+
/** Actual browser callback URL, not a client-supplied asserted return URL. */
|
|
873
|
+
readonly callbackUrl: string;
|
|
874
|
+
readonly expectedReturnTo: string;
|
|
875
|
+
readonly expectedState: string;
|
|
876
|
+
/** Inject the registry-backed HotStore; there is no private Redis client. */
|
|
877
|
+
readonly hotStore: HotStoreShape;
|
|
878
|
+
readonly namespace: string;
|
|
879
|
+
readonly multiNode?: boolean;
|
|
880
|
+
readonly maxNonceAgeMs?: number;
|
|
881
|
+
readonly clockSkewMs?: number;
|
|
882
|
+
readonly now?: () => number;
|
|
883
|
+
readonly fetchImpl?: typeof fetch;
|
|
884
|
+
/** How long Steam may take to answer. Default 5000 ms. */
|
|
885
|
+
readonly timeoutMs?: number;
|
|
886
|
+
/** Loopback fixture only; the asserted OP remains pinned to Steam. */
|
|
887
|
+
readonly verificationUrl?: string;
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
export declare interface SteamOpenIdHandoff {
|
|
891
|
+
readonly url: string;
|
|
892
|
+
readonly state: string;
|
|
893
|
+
readonly returnTo: string;
|
|
894
|
+
readonly realm: string;
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
/**
|
|
898
|
+
* Steam: the game calls `ISteamUser::GetAuthTicketForWebApi(identity)` and sends
|
|
899
|
+
* the ticket as hex; the server asks Steam's partner API who it belongs to. The
|
|
900
|
+
* account id is the player's SteamID64 — also for a family-shared copy, whose
|
|
901
|
+
* owner is a different account.
|
|
902
|
+
*/
|
|
903
|
+
export declare const steamPlatformLogin: (options?: SteamPlatformLoginOptions) => PlatformLogin;
|
|
904
|
+
|
|
905
|
+
export declare interface SteamPlatformLoginOptions {
|
|
906
|
+
/** Steam App ID. Default: `VOLTRO_STEAM_APP_ID`. */
|
|
907
|
+
readonly appId?: number;
|
|
908
|
+
/** The identity string the game passes to `GetAuthTicketForWebApi`. Default `voltro`. */
|
|
909
|
+
readonly identity?: string;
|
|
910
|
+
/** Steamworks Web API publisher key. Default: `VOLTRO_STEAM_PUBLISHER_KEY`. Never ships to clients. */
|
|
911
|
+
readonly publisherKey?: string;
|
|
912
|
+
/** How long Steam may take to answer before the sign-in answers 502. Default 5000 ms. */
|
|
913
|
+
readonly timeoutMs?: number;
|
|
914
|
+
/** Sign in players the publisher banned from this app. Default false: they are refused with 403. */
|
|
915
|
+
readonly allowPublisherBanned?: boolean;
|
|
916
|
+
/** Test seam — a loopback stand-in for the partner API. */
|
|
917
|
+
readonly verificationUrl?: string;
|
|
918
|
+
readonly fetchImpl?: typeof fetch;
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
export declare interface SteamWebApiTicketOptions {
|
|
922
|
+
readonly ticket: string;
|
|
923
|
+
readonly appId: number;
|
|
924
|
+
readonly identity: string;
|
|
925
|
+
readonly publisherKey: string;
|
|
926
|
+
readonly fetchImpl?: typeof fetch;
|
|
927
|
+
/** How long Steam may take to answer. Default 5000 ms. */
|
|
928
|
+
readonly timeoutMs?: number;
|
|
929
|
+
/** Accept a player the publisher banned from this app. Default false. */
|
|
930
|
+
readonly allowPublisherBanned?: boolean;
|
|
931
|
+
/** Loopback fixture only. The production verifier is the publisher API. */
|
|
932
|
+
readonly verificationUrl?: string;
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
/** Run a platform verifier and sort its failure into refused (401) or unavailable (503). */
|
|
936
|
+
export declare const verifyPlatformTicket: (platform: PlatformLogin, ticket: string) => Promise<PlatformAccount>;
|
|
937
|
+
|
|
938
|
+
/** Steamworks GetAuthTicketForWebApi hex tickets, verified on the secure
|
|
939
|
+
* server against the configured app and identity. No supplied SteamID wins. */
|
|
940
|
+
export declare const verifySteamWebApiTicket: (options: SteamWebApiTicketOptions) => Promise<SocialProfile>;
|
|
941
|
+
|
|
666
942
|
export { }
|