@account-kit/signer 4.17.0 → 4.18.0-alpha.4

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.
Files changed (61) hide show
  1. package/dist/esm/base.d.ts +1 -0
  2. package/dist/esm/base.js +34 -0
  3. package/dist/esm/base.js.map +1 -1
  4. package/dist/esm/client/base.d.ts +3 -2
  5. package/dist/esm/client/base.js +15 -20
  6. package/dist/esm/client/base.js.map +1 -1
  7. package/dist/esm/client/index.d.ts +27 -1
  8. package/dist/esm/client/index.js +35 -0
  9. package/dist/esm/client/index.js.map +1 -1
  10. package/dist/esm/client/types.d.ts +18 -1
  11. package/dist/esm/client/types.js.map +1 -1
  12. package/dist/esm/metrics.d.ts +3 -0
  13. package/dist/esm/metrics.js.map +1 -1
  14. package/dist/esm/oauth.d.ts +5 -4
  15. package/dist/esm/oauth.js +16 -6
  16. package/dist/esm/oauth.js.map +1 -1
  17. package/dist/esm/session/manager.js +4 -0
  18. package/dist/esm/session/manager.js.map +1 -1
  19. package/dist/esm/session/types.d.ts +1 -1
  20. package/dist/esm/session/types.js.map +1 -1
  21. package/dist/esm/signer.d.ts +6 -2
  22. package/dist/esm/signer.js.map +1 -1
  23. package/dist/esm/types.d.ts +2 -1
  24. package/dist/esm/types.js +1 -0
  25. package/dist/esm/types.js.map +1 -1
  26. package/dist/esm/version.d.ts +1 -1
  27. package/dist/esm/version.js +1 -1
  28. package/dist/esm/version.js.map +1 -1
  29. package/dist/types/base.d.ts +1 -0
  30. package/dist/types/base.d.ts.map +1 -1
  31. package/dist/types/client/base.d.ts +3 -2
  32. package/dist/types/client/base.d.ts.map +1 -1
  33. package/dist/types/client/index.d.ts +27 -1
  34. package/dist/types/client/index.d.ts.map +1 -1
  35. package/dist/types/client/types.d.ts +18 -1
  36. package/dist/types/client/types.d.ts.map +1 -1
  37. package/dist/types/metrics.d.ts +3 -0
  38. package/dist/types/metrics.d.ts.map +1 -1
  39. package/dist/types/oauth.d.ts +5 -4
  40. package/dist/types/oauth.d.ts.map +1 -1
  41. package/dist/types/session/manager.d.ts.map +1 -1
  42. package/dist/types/session/types.d.ts +1 -1
  43. package/dist/types/session/types.d.ts.map +1 -1
  44. package/dist/types/signer.d.ts +6 -2
  45. package/dist/types/signer.d.ts.map +1 -1
  46. package/dist/types/types.d.ts +2 -1
  47. package/dist/types/types.d.ts.map +1 -1
  48. package/dist/types/version.d.ts +1 -1
  49. package/dist/types/version.d.ts.map +1 -1
  50. package/package.json +4 -4
  51. package/src/base.ts +34 -0
  52. package/src/client/base.ts +25 -22
  53. package/src/client/index.ts +40 -0
  54. package/src/client/types.ts +20 -1
  55. package/src/metrics.ts +2 -1
  56. package/src/oauth.ts +22 -8
  57. package/src/session/manager.ts +7 -2
  58. package/src/session/types.ts +1 -1
  59. package/src/signer.ts +11 -1
  60. package/src/types.ts +1 -0
  61. package/src/version.ts +1 -1
@@ -4,7 +4,7 @@ import EventEmitter from "eventemitter3";
4
4
  import { jwtDecode } from "jwt-decode";
5
5
  import { sha256, type Hex } from "viem";
6
6
  import { NotAuthenticatedError, OAuthProvidersError } from "../errors.js";
7
- import { addOpenIdIfAbsent, getDefaultScopeAndClaims } from "../oauth.js";
7
+ import { getDefaultProviderCustomization } from "../oauth.js";
8
8
  import type { OauthMode } from "../signer.js";
9
9
  import { base64UrlEncode } from "../utils/base64UrlEncode.js";
10
10
  import { resolveRelativeUrl } from "../utils/resolveRelativeUrl.js";
@@ -17,6 +17,8 @@ import type {
17
17
  EmailAuthParams,
18
18
  GetOauthProviderUrlArgs,
19
19
  GetWebAuthnAttestationResult,
20
+ JwtParams,
21
+ JwtResponse,
20
22
  OauthConfig,
21
23
  OauthParams,
22
24
  OauthState,
@@ -27,6 +29,7 @@ import type {
27
29
  SignupResponse,
28
30
  User,
29
31
  } from "./types.js";
32
+ import { VERSION } from "../version.js";
30
33
 
31
34
  export interface BaseSignerClientParams {
32
35
  stamper: TurnkeyClient["stamper"];
@@ -153,6 +156,10 @@ export abstract class BaseSignerClient<TExportWalletParams = unknown> {
153
156
  args: Omit<OtpParams, "targetPublicKey">
154
157
  ): Promise<{ bundle: string }>;
155
158
 
159
+ public abstract submitJwt(
160
+ args: Omit<JwtParams, "targetPublicKey">
161
+ ): Promise<JwtResponse>;
162
+
156
163
  public abstract disconnect(): Promise<void>;
157
164
 
158
165
  public abstract exportWallet(params: TExportWalletParams): Promise<boolean>;
@@ -382,6 +389,7 @@ export abstract class BaseSignerClient<TExportWalletParams = unknown> {
382
389
  const basePath = "/signer";
383
390
 
384
391
  const headers = new Headers();
392
+ headers.append("Alchemy-AA-Sdk-Version", VERSION);
385
393
  headers.append("Content-Type", "application/json");
386
394
  if (this.connectionConfig.apiKey) {
387
395
  headers.append("Authorization", `Bearer ${this.connectionConfig.apiKey}`);
@@ -540,6 +548,7 @@ export abstract class BaseSignerClient<TExportWalletParams = unknown> {
540
548
  auth0Connection,
541
549
  scope: providedScope,
542
550
  claims: providedClaims,
551
+ otherParameters: providedOtherParameters,
543
552
  mode,
544
553
  redirectUrl,
545
554
  expirationSeconds,
@@ -562,23 +571,20 @@ export abstract class BaseSignerClient<TExportWalletParams = unknown> {
562
571
  throw new Error(`No auth provider found with id ${authProviderId}`);
563
572
  }
564
573
 
565
- let scope: string;
566
- let claims: string | undefined;
567
-
568
- if (providedScope) {
569
- scope = addOpenIdIfAbsent(providedScope);
570
- claims = providedClaims;
571
- } else {
572
- if (isCustomProvider) {
573
- throw new Error("scope must be provided for a custom provider");
574
- }
575
- const scopeAndClaims = getDefaultScopeAndClaims(authProviderId);
576
- if (!scopeAndClaims) {
577
- throw new Error(
578
- `Default scope not known for provider ${authProviderId}`
579
- );
580
- }
581
- ({ scope, claims } = scopeAndClaims);
574
+ let scope: string | undefined = providedScope;
575
+ let claims: string | undefined = providedClaims;
576
+ let otherParameters: Record<string, string> | undefined =
577
+ providedOtherParameters;
578
+
579
+ if (!isCustomProvider) {
580
+ const defaultCustomization =
581
+ getDefaultProviderCustomization(authProviderId);
582
+ scope ??= defaultCustomization?.scope;
583
+ claims ??= defaultCustomization?.claims;
584
+ otherParameters ??= defaultCustomization?.otherParameters;
585
+ }
586
+ if (!scope) {
587
+ throw new Error(`Default scope not known for provider ${authProviderId}`);
582
588
  }
583
589
  const { authEndpoint, clientId } = authProvider;
584
590
 
@@ -611,10 +617,7 @@ export abstract class BaseSignerClient<TExportWalletParams = unknown> {
611
617
  prompt: "select_account",
612
618
  client_id: clientId,
613
619
  nonce,
614
- // Fixes Facebook mobile login so that `window.opener` doesn't get nullified.
615
- ...(mode === "popup" && authProvider.id === "facebook"
616
- ? { sdk: "joey" }
617
- : {}),
620
+ ...otherParameters,
618
621
  };
619
622
  if (claims) {
620
623
  params.claims = claims;
@@ -14,8 +14,10 @@ import type {
14
14
  CredentialCreationOptionOverrides,
15
15
  EmailAuthParams,
16
16
  ExportWalletParams,
17
+ JwtParams,
17
18
  OauthConfig,
18
19
  OtpParams,
20
+ JwtResponse,
19
21
  User,
20
22
  } from "./types.js";
21
23
 
@@ -245,6 +247,44 @@ export class AlchemySignerWebClient extends BaseSignerClient<ExportWalletParams>
245
247
  return { bundle: credentialBundle };
246
248
  }
247
249
 
250
+ /**
251
+ * Authenticates using a custom issued JWT
252
+ *
253
+ * @example
254
+ * ```ts
255
+ * import { AlchemySignerWebClient } from "@account-kit/signer";
256
+ *
257
+ * const client = new AlchemySignerWebClient({
258
+ * connection: {
259
+ * apiKey: "your-api-key",
260
+ * },
261
+ * iframeConfig: {
262
+ * iframeContainerId: "signer-iframe-container",
263
+ * },
264
+ * });
265
+ *
266
+ * const account = await client.submitJwt({
267
+ * jwt: "custom-issued-jwt",
268
+ * authProvider: "auth-provider-name",
269
+ * });
270
+ * ```
271
+ *
272
+ * @param {Omit<JwtParams, "targetPublicKey">} args The parameters for the JWT request, excluding the target public key.
273
+ * @returns {Promise<{ bundle: string }>} A promise that resolves to an object containing the credential bundle.
274
+ */
275
+ public override async submitJwt(
276
+ args: Omit<JwtParams, "targetPublicKey">
277
+ ): Promise<JwtResponse> {
278
+ this.eventEmitter.emit("authenticating", { type: "custom-jwt" });
279
+ const targetPublicKey = await this.initIframeStamper();
280
+ return this.request("/v1/auth-jwt", {
281
+ jwt: args.jwt,
282
+ targetPublicKey,
283
+ authProvider: args.authProvider,
284
+ expirationSeconds: args?.expirationSeconds,
285
+ });
286
+ }
287
+
248
288
  /**
249
289
  * Completes auth for the user by injecting a credential bundle and retrieving
250
290
  * the user information based on the provided organization ID. Emits events
@@ -68,6 +68,19 @@ export type OtpParams = {
68
68
  expirationSeconds?: number;
69
69
  };
70
70
 
71
+ export type JwtParams = {
72
+ jwt: string;
73
+ targetPublicKey: string;
74
+ authProvider: string;
75
+ expirationSeconds?: number;
76
+ };
77
+
78
+ export type JwtResponse = {
79
+ isSignUp: boolean;
80
+ orgId: string;
81
+ credentialBundle: string;
82
+ };
83
+
71
84
  export type SignupResponse = {
72
85
  orgId: string;
73
86
  userId?: string;
@@ -168,6 +181,11 @@ export type SignerEndpoints = [
168
181
  Body: OtpParams;
169
182
  Response: { credentialBundle: string };
170
183
  },
184
+ {
185
+ Route: "/v1/auth-jwt";
186
+ Body: JwtParams;
187
+ Response: JwtResponse;
188
+ },
171
189
  {
172
190
  Route: "/v1/signer-config";
173
191
  Body: {};
@@ -176,7 +194,7 @@ export type SignerEndpoints = [
176
194
  ];
177
195
 
178
196
  export type AuthenticatingEventMetadata = {
179
- type: "email" | "passkey" | "oauth" | "otp" | "otpVerify";
197
+ type: "email" | "passkey" | "oauth" | "otp" | "otpVerify" | "custom-jwt";
180
198
  };
181
199
 
182
200
  export type AlchemySignerClientEvents = {
@@ -187,6 +205,7 @@ export type AlchemySignerClientEvents = {
187
205
  connectedPasskey(user: User): void;
188
206
  connectedOauth(user: User, bundle: string): void;
189
207
  connectedOtp(user: User, bundle: string): void;
208
+ connectedJwt(user: User, bundle: string): void;
190
209
  disconnected(): void;
191
210
  };
192
211
 
package/src/metrics.ts CHANGED
@@ -14,7 +14,8 @@ export type SignerEventsSchema = [
14
14
  | "oauthReturn";
15
15
  provider?: never;
16
16
  }
17
- | { authType: "oauth"; provider: string };
17
+ | { authType: "oauth"; provider: string }
18
+ | { authType: "custom-jwt"; provider: string };
18
19
  },
19
20
  {
20
21
  EventName: "signer_sign_message";
package/src/oauth.ts CHANGED
@@ -1,27 +1,41 @@
1
1
  import type { KnownAuthProvider } from "./signer";
2
2
 
3
- export type ScopeAndClaims = {
3
+ export type AuthProviderCustomization = {
4
4
  scope: string;
5
5
  claims?: string;
6
+ otherParameters?: Record<string, string>;
6
7
  };
7
8
 
8
- const DEFAULT_SCOPE_AND_CLAIMS: Record<KnownAuthProvider, ScopeAndClaims> = {
9
+ const DEFAULT_PROVIDER_CUSTOMIZATION: Record<
10
+ KnownAuthProvider,
11
+ AuthProviderCustomization
12
+ > = {
9
13
  google: { scope: "openid email" },
10
14
  apple: { scope: "openid email" },
11
- facebook: { scope: "openid email" },
15
+ facebook: {
16
+ scope: "openid email",
17
+ // Fixes Facebook mobile login so that `window.opener` doesn't get nullified.
18
+ otherParameters: { sdk: "joey" },
19
+ },
20
+ twitch: {
21
+ scope: "openid user:read:email",
22
+ claims: JSON.stringify({ id_token: { email: null } }),
23
+ // Forces Twitch to show the login page even if the user is already logged in.
24
+ otherParameters: { force_verify: "true" },
25
+ },
12
26
  auth0: { scope: "openid email" },
13
27
  };
14
28
 
15
29
  /**
16
- * Returns the default scope and claims when using a known auth provider
30
+ * Returns the default customization parameters when using a known auth provider
17
31
  *
18
32
  * @param {string} knownAuthProviderId id of a known auth provider, e.g. "google"
19
- * @returns {ScopeAndClaims | undefined} default scope and claims
33
+ * @returns {AuthProviderCustomization | undefined} default customization parameters
20
34
  */
21
- export function getDefaultScopeAndClaims(
35
+ export function getDefaultProviderCustomization(
22
36
  knownAuthProviderId: KnownAuthProvider
23
- ): ScopeAndClaims | undefined {
24
- return DEFAULT_SCOPE_AND_CLAIMS[knownAuthProviderId];
37
+ ): AuthProviderCustomization | undefined {
38
+ return DEFAULT_PROVIDER_CUSTOMIZATION[knownAuthProviderId];
25
39
  }
26
40
 
27
41
  /**
@@ -92,6 +92,7 @@ export class SessionManager {
92
92
  switch (existingSession.type) {
93
93
  case "email":
94
94
  case "oauth":
95
+ case "custom-jwt":
95
96
  case "otp": {
96
97
  const connectedEventName = (() => {
97
98
  switch (existingSession.type) {
@@ -101,6 +102,8 @@ export class SessionManager {
101
102
  return "connectedOauth";
102
103
  case "otp":
103
104
  return "connectedOtp";
105
+ case "custom-jwt":
106
+ return "connectedJwt";
104
107
  }
105
108
  })();
106
109
  const result = await this.client
@@ -203,7 +206,7 @@ export class SessionManager {
203
206
  private setSession = (
204
207
  session_:
205
208
  | Omit<
206
- Extract<Session, { type: "email" | "oauth" | "otp" }>,
209
+ Extract<Session, { type: "email" | "oauth" | "otp" | "custom-jwt" }>,
207
210
  "expirationDateMs"
208
211
  >
209
212
  | Omit<Extract<Session, { type: "passkey" }>, "expirationDateMs">
@@ -276,6 +279,8 @@ export class SessionManager {
276
279
  },
277
280
  connectedOauth: (user, bundle) =>
278
281
  this.setSessionWithUserAndBundle({ type: "oauth", user, bundle }),
282
+ connectedJwt: (user, bundle) =>
283
+ this.setSessionWithUserAndBundle({ type: "custom-jwt", user, bundle }),
279
284
  connectedOtp: (user, bundle) => {
280
285
  this.setSessionWithUserAndBundle({ type: "otp", user, bundle });
281
286
  },
@@ -331,7 +336,7 @@ export class SessionManager {
331
336
  user,
332
337
  bundle,
333
338
  }: {
334
- type: "email" | "oauth" | "otp";
339
+ type: "email" | "oauth" | "otp" | "custom-jwt";
335
340
  user: User;
336
341
  bundle: string;
337
342
  }) => {
@@ -2,7 +2,7 @@ import type { User } from "../client/types";
2
2
 
3
3
  export type Session =
4
4
  | {
5
- type: "email" | "oauth" | "otp";
5
+ type: "email" | "oauth" | "otp" | "custom-jwt";
6
6
  bundle: string;
7
7
  expirationDateMs: number;
8
8
  user: User;
package/src/signer.ts CHANGED
@@ -35,8 +35,13 @@ export type AuthParams =
35
35
  type: "oauth";
36
36
  scope?: string;
37
37
  claims?: string;
38
+ otherParameters?: Record<string, string>;
38
39
  } & OauthProviderConfig &
39
40
  OauthRedirectConfig)
41
+ | ({
42
+ type: "custom-jwt";
43
+ jwt: string;
44
+ } & OauthProviderConfig)
40
45
  | {
41
46
  type: "oauthReturn";
42
47
  bundle: string;
@@ -70,7 +75,12 @@ export type OauthRedirectConfig =
70
75
  | { mode: "redirect"; redirectUrl: string }
71
76
  | { mode: "popup"; redirectUrl?: never };
72
77
 
73
- export type KnownAuthProvider = "google" | "apple" | "facebook" | "auth0";
78
+ export type KnownAuthProvider =
79
+ | "google"
80
+ | "apple"
81
+ | "facebook"
82
+ | "twitch"
83
+ | "auth0";
74
84
 
75
85
  export type OauthMode = "redirect" | "popup";
76
86
 
package/src/types.ts CHANGED
@@ -19,6 +19,7 @@ export enum AlchemySignerStatus {
19
19
  AUTHENTICATING_OAUTH = "AUTHENTICATING_OAUTH",
20
20
  AWAITING_EMAIL_AUTH = "AWAITING_EMAIL_AUTH",
21
21
  AWAITING_OTP_AUTH = "AWAITING_OTP_AUTH",
22
+ AUTHENTICATING_JWT = "AUTHENTICATING_JWT",
22
23
  }
23
24
 
24
25
  export interface ErrorInfo {
package/src/version.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  // This file is autogenerated by inject-version.ts. Any changes will be
2
2
  // overwritten on commit!
3
- export const VERSION = "4.17.0";
3
+ export const VERSION = "4.18.0-alpha.4";