@account-kit/signer 4.9.0 → 4.11.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/dist/esm/client/base.d.ts +45 -3
- package/dist/esm/client/base.js +141 -1
- package/dist/esm/client/base.js.map +1 -1
- package/dist/esm/client/index.d.ts +0 -2
- package/dist/esm/client/index.js +15 -103
- package/dist/esm/client/index.js.map +1 -1
- package/dist/esm/client/types.d.ts +16 -0
- package/dist/esm/client/types.js.map +1 -1
- package/dist/esm/errors.js +3 -1
- package/dist/esm/errors.js.map +1 -1
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/oauth.d.ts +8 -7
- package/dist/esm/oauth.js +10 -10
- package/dist/esm/oauth.js.map +1 -1
- package/dist/esm/utils/resolveRelativeUrl.d.ts +1 -0
- package/dist/esm/utils/resolveRelativeUrl.js +7 -0
- package/dist/esm/utils/resolveRelativeUrl.js.map +1 -0
- package/dist/esm/version.d.ts +1 -1
- package/dist/esm/version.js +1 -1
- package/dist/esm/version.js.map +1 -1
- package/dist/types/client/base.d.ts +45 -3
- package/dist/types/client/base.d.ts.map +1 -1
- package/dist/types/client/index.d.ts +0 -2
- package/dist/types/client/index.d.ts.map +1 -1
- package/dist/types/client/types.d.ts +16 -0
- package/dist/types/client/types.d.ts.map +1 -1
- package/dist/types/errors.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/oauth.d.ts +8 -7
- package/dist/types/oauth.d.ts.map +1 -1
- package/dist/types/utils/resolveRelativeUrl.d.ts +2 -0
- package/dist/types/utils/resolveRelativeUrl.d.ts.map +1 -0
- package/dist/types/version.d.ts +1 -1
- package/dist/types/version.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/client/base.ts +170 -4
- package/src/client/index.ts +18 -128
- package/src/client/types.ts +24 -2
- package/src/errors.ts +3 -1
- package/src/index.ts +1 -0
- package/src/oauth.ts +11 -11
- package/src/utils/resolveRelativeUrl.ts +6 -0
- package/src/version.ts +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../src/version.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,OAAO,
|
|
1
|
+
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../src/version.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,OAAO,WAAW,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@account-kit/signer",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.11.0",
|
|
4
4
|
"description": "Core interfaces and clients for interfacing with the Alchemy Signer API",
|
|
5
5
|
"author": "Alchemy",
|
|
6
6
|
"license": "MIT",
|
|
@@ -49,8 +49,8 @@
|
|
|
49
49
|
"vitest": "^2.0.4"
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@aa-sdk/core": "^4.
|
|
53
|
-
"@account-kit/logging": "^4.
|
|
52
|
+
"@aa-sdk/core": "^4.11.0",
|
|
53
|
+
"@account-kit/logging": "^4.11.0",
|
|
54
54
|
"@turnkey/http": "^2.6.2",
|
|
55
55
|
"@turnkey/iframe-stamper": "^1.0.0",
|
|
56
56
|
"@turnkey/viem": "^0.4.8",
|
|
@@ -73,5 +73,5 @@
|
|
|
73
73
|
"url": "https://github.com/alchemyplatform/aa-sdk/issues"
|
|
74
74
|
},
|
|
75
75
|
"homepage": "https://github.com/alchemyplatform/aa-sdk#readme",
|
|
76
|
-
"gitHead": "
|
|
76
|
+
"gitHead": "789a1db1e3cfdca61393d8328693dd9d1a4ebb0f"
|
|
77
77
|
}
|
package/src/client/base.ts
CHANGED
|
@@ -2,19 +2,22 @@ import { ConnectionConfigSchema, type ConnectionConfig } from "@aa-sdk/core";
|
|
|
2
2
|
import { TurnkeyClient, type TSignedRequest } from "@turnkey/http";
|
|
3
3
|
import EventEmitter from "eventemitter3";
|
|
4
4
|
import { jwtDecode } from "jwt-decode";
|
|
5
|
-
import type
|
|
6
|
-
import { NotAuthenticatedError } from "../errors.js";
|
|
5
|
+
import { sha256, type Hex } from "viem";
|
|
6
|
+
import { NotAuthenticatedError, OAuthProvidersError } from "../errors.js";
|
|
7
7
|
import { base64UrlEncode } from "../utils/base64UrlEncode.js";
|
|
8
8
|
import { assertNever } from "../utils/typeAssertions.js";
|
|
9
|
+
import { resolveRelativeUrl } from "../utils/resolveRelativeUrl.js";
|
|
9
10
|
import type {
|
|
10
11
|
AlchemySignerClientEvent,
|
|
11
12
|
AlchemySignerClientEvents,
|
|
12
13
|
AuthenticatingEventMetadata,
|
|
13
14
|
CreateAccountParams,
|
|
14
15
|
EmailAuthParams,
|
|
16
|
+
GetOauthProviderUrlArgs,
|
|
15
17
|
GetWebAuthnAttestationResult,
|
|
16
18
|
OauthConfig,
|
|
17
19
|
OauthParams,
|
|
20
|
+
OauthState,
|
|
18
21
|
OtpParams,
|
|
19
22
|
SignerBody,
|
|
20
23
|
SignerResponse,
|
|
@@ -22,6 +25,8 @@ import type {
|
|
|
22
25
|
SignupResponse,
|
|
23
26
|
User,
|
|
24
27
|
} from "./types.js";
|
|
28
|
+
import type { OauthMode } from "../signer.js";
|
|
29
|
+
import { addOpenIdIfAbsent, getDefaultScopeAndClaims } from "../oauth.js";
|
|
25
30
|
|
|
26
31
|
export interface BaseSignerClientParams {
|
|
27
32
|
stamper: TurnkeyClient["stamper"];
|
|
@@ -46,7 +51,6 @@ export abstract class BaseSignerClient<TExportWalletParams = unknown> {
|
|
|
46
51
|
protected rootOrg: string;
|
|
47
52
|
protected eventEmitter: EventEmitter<AlchemySignerClientEvents>;
|
|
48
53
|
protected oauthConfig: OauthConfig | undefined;
|
|
49
|
-
|
|
50
54
|
/**
|
|
51
55
|
* Create a new instance of the Alchemy Signer client
|
|
52
56
|
*
|
|
@@ -139,7 +143,7 @@ export abstract class BaseSignerClient<TExportWalletParams = unknown> {
|
|
|
139
143
|
|
|
140
144
|
public abstract oauthWithRedirect(
|
|
141
145
|
args: Extract<OauthParams, { mode: "redirect" }>
|
|
142
|
-
): Promise<never>;
|
|
146
|
+
): Promise<User | never>;
|
|
143
147
|
|
|
144
148
|
public abstract oauthWithPopup(
|
|
145
149
|
args: Extract<OauthParams, { mode: "popup" }>
|
|
@@ -471,6 +475,158 @@ export abstract class BaseSignerClient<TExportWalletParams = unknown> {
|
|
|
471
475
|
return result;
|
|
472
476
|
};
|
|
473
477
|
|
|
478
|
+
/**
|
|
479
|
+
* Returns the authentication url for the selected OAuth Proivder
|
|
480
|
+
*
|
|
481
|
+
* @example
|
|
482
|
+
* ```ts
|
|
483
|
+
*
|
|
484
|
+
* cosnt oauthParams = {
|
|
485
|
+
* authProviderId: "google",
|
|
486
|
+
* isCustomProvider: false,
|
|
487
|
+
* auth0Connection: undefined,
|
|
488
|
+
* scope: undefined,
|
|
489
|
+
* claims: undefined,
|
|
490
|
+
* mode: "redirect",
|
|
491
|
+
* redirectUrl: "https://your-url-path/oauth-return",
|
|
492
|
+
* expirationSeconds: 3000
|
|
493
|
+
* };
|
|
494
|
+
*
|
|
495
|
+
* const turnkeyPublicKey = await this.initIframeStamper();
|
|
496
|
+
* const oauthCallbackUrl = this.oauthCallbackUrl;
|
|
497
|
+
* const oauthConfig = this.getOauthConfig() // Optional value for OauthConfig()
|
|
498
|
+
* const usesRelativeUrl = true // Optional value to determine if we use a relative (or absolute) url for the `redirect_url`
|
|
499
|
+
*
|
|
500
|
+
* const oauthProviderUrl = getOauthProviderUrl({
|
|
501
|
+
* oauthParams,
|
|
502
|
+
* turnkeyPublicKey,
|
|
503
|
+
* oauthCallbackUrl
|
|
504
|
+
* })
|
|
505
|
+
*
|
|
506
|
+
* ```
|
|
507
|
+
* @param {GetOauthProviderUrlArgs} args Required. The Oauth provider's auth parameters
|
|
508
|
+
*
|
|
509
|
+
* @returns {Promise<string>} returns the Oauth provider's url
|
|
510
|
+
*/
|
|
511
|
+
protected getOauthProviderUrl = async (
|
|
512
|
+
args: GetOauthProviderUrlArgs
|
|
513
|
+
): Promise<string> => {
|
|
514
|
+
const {
|
|
515
|
+
oauthParams,
|
|
516
|
+
turnkeyPublicKey,
|
|
517
|
+
oauthCallbackUrl,
|
|
518
|
+
oauthConfig,
|
|
519
|
+
usesRelativeUrl = true,
|
|
520
|
+
} = args;
|
|
521
|
+
|
|
522
|
+
const {
|
|
523
|
+
authProviderId,
|
|
524
|
+
isCustomProvider,
|
|
525
|
+
auth0Connection,
|
|
526
|
+
scope: providedScope,
|
|
527
|
+
claims: providedClaims,
|
|
528
|
+
mode,
|
|
529
|
+
redirectUrl,
|
|
530
|
+
expirationSeconds,
|
|
531
|
+
} = oauthParams;
|
|
532
|
+
|
|
533
|
+
const { codeChallenge, requestKey, authProviders } =
|
|
534
|
+
oauthConfig ?? (await this.getOauthConfigForMode(mode));
|
|
535
|
+
|
|
536
|
+
if (!authProviders) {
|
|
537
|
+
throw new OAuthProvidersError();
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
const authProvider = authProviders.find(
|
|
541
|
+
(provider) =>
|
|
542
|
+
provider.id === authProviderId &&
|
|
543
|
+
!!provider.isCustomProvider === !!isCustomProvider
|
|
544
|
+
);
|
|
545
|
+
|
|
546
|
+
if (!authProvider) {
|
|
547
|
+
throw new Error(`No auth provider found with id ${authProviderId}`);
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
let scope: string;
|
|
551
|
+
let claims: string | undefined;
|
|
552
|
+
|
|
553
|
+
if (providedScope) {
|
|
554
|
+
scope = addOpenIdIfAbsent(providedScope);
|
|
555
|
+
claims = providedClaims;
|
|
556
|
+
} else {
|
|
557
|
+
if (isCustomProvider) {
|
|
558
|
+
throw new Error("scope must be provided for a custom provider");
|
|
559
|
+
}
|
|
560
|
+
const scopeAndClaims = getDefaultScopeAndClaims(authProviderId);
|
|
561
|
+
if (!scopeAndClaims) {
|
|
562
|
+
throw new Error(
|
|
563
|
+
`Default scope not known for provider ${authProviderId}`
|
|
564
|
+
);
|
|
565
|
+
}
|
|
566
|
+
({ scope, claims } = scopeAndClaims);
|
|
567
|
+
}
|
|
568
|
+
const { authEndpoint, clientId } = authProvider;
|
|
569
|
+
|
|
570
|
+
const nonce = this.getOauthNonce(turnkeyPublicKey);
|
|
571
|
+
const stateObject: OauthState = {
|
|
572
|
+
authProviderId,
|
|
573
|
+
isCustomProvider,
|
|
574
|
+
requestKey,
|
|
575
|
+
turnkeyPublicKey,
|
|
576
|
+
expirationSeconds,
|
|
577
|
+
redirectUrl:
|
|
578
|
+
mode === "redirect"
|
|
579
|
+
? usesRelativeUrl
|
|
580
|
+
? resolveRelativeUrl(redirectUrl)
|
|
581
|
+
: redirectUrl
|
|
582
|
+
: undefined,
|
|
583
|
+
openerOrigin: mode === "popup" ? window.location.origin : undefined,
|
|
584
|
+
};
|
|
585
|
+
const state = base64UrlEncode(
|
|
586
|
+
new TextEncoder().encode(JSON.stringify(stateObject))
|
|
587
|
+
);
|
|
588
|
+
const authUrl = new URL(authEndpoint);
|
|
589
|
+
const params: Record<string, string> = {
|
|
590
|
+
redirect_uri: oauthCallbackUrl,
|
|
591
|
+
response_type: "code",
|
|
592
|
+
scope,
|
|
593
|
+
state,
|
|
594
|
+
code_challenge: codeChallenge,
|
|
595
|
+
code_challenge_method: "S256",
|
|
596
|
+
prompt: "select_account",
|
|
597
|
+
client_id: clientId,
|
|
598
|
+
nonce,
|
|
599
|
+
};
|
|
600
|
+
if (claims) {
|
|
601
|
+
params.claims = claims;
|
|
602
|
+
}
|
|
603
|
+
if (auth0Connection) {
|
|
604
|
+
params.connection = auth0Connection;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
Object.keys(params).forEach((param) => {
|
|
608
|
+
params[param] && authUrl.searchParams.append(param, params[param]);
|
|
609
|
+
});
|
|
610
|
+
|
|
611
|
+
const [urlPath, searchParams] = authUrl.href.split("?");
|
|
612
|
+
|
|
613
|
+
return `${urlPath?.replace(/\/$/, "")}?${searchParams}`;
|
|
614
|
+
};
|
|
615
|
+
|
|
616
|
+
private getOauthConfigForMode = async (
|
|
617
|
+
mode: OauthMode
|
|
618
|
+
): Promise<OauthConfig> => {
|
|
619
|
+
if (this.oauthConfig) {
|
|
620
|
+
return this.oauthConfig;
|
|
621
|
+
} else if (mode === "redirect") {
|
|
622
|
+
return this.initOauth();
|
|
623
|
+
} else {
|
|
624
|
+
throw new Error(
|
|
625
|
+
"enablePopupOauth must be set in configuration or signer.preparePopupOauth must be called before using popup-based OAuth login"
|
|
626
|
+
);
|
|
627
|
+
}
|
|
628
|
+
};
|
|
629
|
+
|
|
474
630
|
// eslint-disable-next-line eslint-rules/require-jsdoc-on-reexported-functions
|
|
475
631
|
protected pollActivityCompletion = async <
|
|
476
632
|
T extends keyof Awaited<
|
|
@@ -520,4 +676,14 @@ export abstract class BaseSignerClient<TExportWalletParams = unknown> {
|
|
|
520
676
|
return this.pollActivityCompletion(activity, organizationId, resultKey);
|
|
521
677
|
};
|
|
522
678
|
// #endregion
|
|
679
|
+
|
|
680
|
+
/**
|
|
681
|
+
* Turnkey requires the nonce in the id token to be in this format.
|
|
682
|
+
*
|
|
683
|
+
* @param {string} turnkeyPublicKey key from a Turnkey iframe
|
|
684
|
+
* @returns {string} nonce to be used in OIDC
|
|
685
|
+
*/
|
|
686
|
+
protected getOauthNonce = (turnkeyPublicKey: string): string => {
|
|
687
|
+
return sha256(new TextEncoder().encode(turnkeyPublicKey)).slice(2);
|
|
688
|
+
};
|
|
523
689
|
}
|
package/src/client/index.ts
CHANGED
|
@@ -3,9 +3,7 @@ import { getWebAuthnAttestation } from "@turnkey/http";
|
|
|
3
3
|
import { IframeStamper } from "@turnkey/iframe-stamper";
|
|
4
4
|
import { WebauthnStamper } from "@turnkey/webauthn-stamper";
|
|
5
5
|
import { z } from "zod";
|
|
6
|
-
import {
|
|
7
|
-
import { getDefaultScopeAndClaims, getOauthNonce } from "../oauth.js";
|
|
8
|
-
import type { AuthParams, OauthMode } from "../signer.js";
|
|
6
|
+
import type { AuthParams } from "../signer.js";
|
|
9
7
|
import { base64UrlEncode } from "../utils/base64UrlEncode.js";
|
|
10
8
|
import { generateRandomBuffer } from "../utils/generateRandomBuffer.js";
|
|
11
9
|
import { BaseSignerClient } from "./base.js";
|
|
@@ -17,7 +15,6 @@ import type {
|
|
|
17
15
|
EmailAuthParams,
|
|
18
16
|
ExportWalletParams,
|
|
19
17
|
OauthConfig,
|
|
20
|
-
OauthParams,
|
|
21
18
|
OtpParams,
|
|
22
19
|
User,
|
|
23
20
|
} from "./types.js";
|
|
@@ -46,16 +43,6 @@ export type AlchemySignerClientParams = z.input<
|
|
|
46
43
|
typeof AlchemySignerClientParamsSchema
|
|
47
44
|
>;
|
|
48
45
|
|
|
49
|
-
type OauthState = {
|
|
50
|
-
authProviderId: string;
|
|
51
|
-
isCustomProvider?: boolean;
|
|
52
|
-
requestKey: string;
|
|
53
|
-
turnkeyPublicKey: string;
|
|
54
|
-
expirationSeconds?: number;
|
|
55
|
-
redirectUrl?: string;
|
|
56
|
-
openerOrigin?: string;
|
|
57
|
-
};
|
|
58
|
-
|
|
59
46
|
/**
|
|
60
47
|
* A lower level client used by the AlchemySigner used to communicate with
|
|
61
48
|
* Alchemy's signer service.
|
|
@@ -462,7 +449,15 @@ export class AlchemySignerWebClient extends BaseSignerClient<ExportWalletParams>
|
|
|
462
449
|
public override oauthWithRedirect = async (
|
|
463
450
|
args: Extract<AuthParams, { type: "oauth"; mode: "redirect" }>
|
|
464
451
|
): Promise<never> => {
|
|
465
|
-
const
|
|
452
|
+
const turnkeyPublicKey = await this.initIframeStamper();
|
|
453
|
+
|
|
454
|
+
const oauthParams = args;
|
|
455
|
+
const providerUrl = await this.getOauthProviderUrl({
|
|
456
|
+
oauthParams,
|
|
457
|
+
turnkeyPublicKey,
|
|
458
|
+
oauthCallbackUrl: this.oauthCallbackUrl,
|
|
459
|
+
});
|
|
460
|
+
|
|
466
461
|
window.location.href = providerUrl;
|
|
467
462
|
return new Promise((_, reject) =>
|
|
468
463
|
setTimeout(() => reject("Failed to redirect to OAuth provider"), 1000)
|
|
@@ -498,7 +493,13 @@ export class AlchemySignerWebClient extends BaseSignerClient<ExportWalletParams>
|
|
|
498
493
|
public override oauthWithPopup = async (
|
|
499
494
|
args: Extract<AuthParams, { type: "oauth"; mode: "popup" }>
|
|
500
495
|
): Promise<User> => {
|
|
501
|
-
const
|
|
496
|
+
const turnkeyPublicKey = await this.initIframeStamper();
|
|
497
|
+
const oauthParams = args;
|
|
498
|
+
const providerUrl = await this.getOauthProviderUrl({
|
|
499
|
+
oauthParams,
|
|
500
|
+
turnkeyPublicKey,
|
|
501
|
+
oauthCallbackUrl: this.oauthCallbackUrl,
|
|
502
|
+
});
|
|
502
503
|
const popup = window.open(
|
|
503
504
|
providerUrl,
|
|
504
505
|
"_blank",
|
|
@@ -556,85 +557,6 @@ export class AlchemySignerWebClient extends BaseSignerClient<ExportWalletParams>
|
|
|
556
557
|
});
|
|
557
558
|
};
|
|
558
559
|
|
|
559
|
-
private getOauthProviderUrl = async (args: OauthParams): Promise<string> => {
|
|
560
|
-
const {
|
|
561
|
-
authProviderId,
|
|
562
|
-
isCustomProvider,
|
|
563
|
-
auth0Connection,
|
|
564
|
-
scope: providedScope,
|
|
565
|
-
claims: providedClaims,
|
|
566
|
-
mode,
|
|
567
|
-
redirectUrl,
|
|
568
|
-
expirationSeconds,
|
|
569
|
-
} = args;
|
|
570
|
-
const { codeChallenge, requestKey, authProviders } =
|
|
571
|
-
await this.getOauthConfigForMode(mode);
|
|
572
|
-
if (!authProviders) {
|
|
573
|
-
throw new OAuthProvidersError();
|
|
574
|
-
}
|
|
575
|
-
const authProvider = authProviders.find(
|
|
576
|
-
(provider) =>
|
|
577
|
-
provider.id === authProviderId &&
|
|
578
|
-
!!provider.isCustomProvider === !!isCustomProvider
|
|
579
|
-
);
|
|
580
|
-
if (!authProvider) {
|
|
581
|
-
throw new Error(`No auth provider found with id ${authProviderId}`);
|
|
582
|
-
}
|
|
583
|
-
let scope: string;
|
|
584
|
-
let claims: string | undefined;
|
|
585
|
-
if (providedScope) {
|
|
586
|
-
scope = addOpenIdIfAbsent(providedScope);
|
|
587
|
-
claims = providedClaims;
|
|
588
|
-
} else {
|
|
589
|
-
if (isCustomProvider) {
|
|
590
|
-
throw new Error("scope must be provided for a custom provider");
|
|
591
|
-
}
|
|
592
|
-
const scopeAndClaims = getDefaultScopeAndClaims(authProviderId);
|
|
593
|
-
if (!scopeAndClaims) {
|
|
594
|
-
throw new Error(
|
|
595
|
-
`Default scope not known for provider ${authProviderId}`
|
|
596
|
-
);
|
|
597
|
-
}
|
|
598
|
-
({ scope, claims } = scopeAndClaims);
|
|
599
|
-
}
|
|
600
|
-
const { authEndpoint, clientId } = authProvider;
|
|
601
|
-
const turnkeyPublicKey = await this.initIframeStamper();
|
|
602
|
-
const nonce = getOauthNonce(turnkeyPublicKey);
|
|
603
|
-
const stateObject: OauthState = {
|
|
604
|
-
authProviderId,
|
|
605
|
-
isCustomProvider,
|
|
606
|
-
requestKey,
|
|
607
|
-
turnkeyPublicKey,
|
|
608
|
-
expirationSeconds,
|
|
609
|
-
redirectUrl:
|
|
610
|
-
mode === "redirect" ? resolveRelativeUrl(redirectUrl) : undefined,
|
|
611
|
-
openerOrigin: mode === "popup" ? window.location.origin : undefined,
|
|
612
|
-
};
|
|
613
|
-
const state = base64UrlEncode(
|
|
614
|
-
new TextEncoder().encode(JSON.stringify(stateObject))
|
|
615
|
-
);
|
|
616
|
-
const authUrl = new URL(authEndpoint);
|
|
617
|
-
const params: Record<string, string> = {
|
|
618
|
-
redirect_uri: this.oauthCallbackUrl,
|
|
619
|
-
response_type: "code",
|
|
620
|
-
scope,
|
|
621
|
-
state,
|
|
622
|
-
code_challenge: codeChallenge,
|
|
623
|
-
code_challenge_method: "S256",
|
|
624
|
-
prompt: "select_account",
|
|
625
|
-
client_id: clientId,
|
|
626
|
-
nonce,
|
|
627
|
-
};
|
|
628
|
-
if (claims) {
|
|
629
|
-
params.claims = claims;
|
|
630
|
-
}
|
|
631
|
-
if (auth0Connection) {
|
|
632
|
-
params.connection = auth0Connection;
|
|
633
|
-
}
|
|
634
|
-
authUrl.search = new URLSearchParams(params).toString();
|
|
635
|
-
return authUrl.toString();
|
|
636
|
-
};
|
|
637
|
-
|
|
638
560
|
private initIframeStamper = async () => {
|
|
639
561
|
if (!this.iframeStamper.publicKey()) {
|
|
640
562
|
await this.iframeStamper.init();
|
|
@@ -720,41 +642,9 @@ export class AlchemySignerWebClient extends BaseSignerClient<ExportWalletParams>
|
|
|
720
642
|
|
|
721
643
|
// swap the stamper back in case the user logged in with a different stamper (passkeys)
|
|
722
644
|
this.setStamper(currentStamper);
|
|
723
|
-
const nonce = getOauthNonce(publicKey);
|
|
645
|
+
const nonce = this.getOauthNonce(publicKey);
|
|
724
646
|
return this.request("/v1/prepare-oauth", { nonce });
|
|
725
647
|
};
|
|
726
|
-
|
|
727
|
-
private getOauthConfigForMode = async (
|
|
728
|
-
mode: OauthMode
|
|
729
|
-
): Promise<OauthConfig> => {
|
|
730
|
-
if (this.oauthConfig) {
|
|
731
|
-
return this.oauthConfig;
|
|
732
|
-
} else if (mode === "redirect") {
|
|
733
|
-
return this.initOauth();
|
|
734
|
-
} else {
|
|
735
|
-
throw new Error(
|
|
736
|
-
"enablePopupOauth must be set in configuration or signer.preparePopupOauth must be called before using popup-based OAuth login"
|
|
737
|
-
);
|
|
738
|
-
}
|
|
739
|
-
};
|
|
740
|
-
}
|
|
741
|
-
|
|
742
|
-
function resolveRelativeUrl(url: string): string {
|
|
743
|
-
// Funny trick.
|
|
744
|
-
const a = document.createElement("a");
|
|
745
|
-
a.href = url;
|
|
746
|
-
return a.href;
|
|
747
|
-
}
|
|
748
|
-
|
|
749
|
-
/**
|
|
750
|
-
* "openid" is a required scope in the OIDC protocol. Insert it if the user
|
|
751
|
-
* forgot.
|
|
752
|
-
*
|
|
753
|
-
* @param {string} scope scope param which may be missing "openid"
|
|
754
|
-
* @returns {string} scope which most definitely contains "openid"
|
|
755
|
-
*/
|
|
756
|
-
function addOpenIdIfAbsent(scope: string): string {
|
|
757
|
-
return scope.match(/\bopenid\b/) ? scope : `openid ${scope}`;
|
|
758
648
|
}
|
|
759
649
|
|
|
760
650
|
/**
|
package/src/client/types.ts
CHANGED
|
@@ -99,7 +99,9 @@ export type SignerEndpoints = [
|
|
|
99
99
|
{
|
|
100
100
|
Route: "/v1/signup";
|
|
101
101
|
Body:
|
|
102
|
-
| (Omit<EmailAuthParams, "redirectParams"> & {
|
|
102
|
+
| (Omit<EmailAuthParams, "redirectParams"> & {
|
|
103
|
+
redirectParams?: string;
|
|
104
|
+
})
|
|
103
105
|
| {
|
|
104
106
|
passkey: {
|
|
105
107
|
challenge: string;
|
|
@@ -117,7 +119,9 @@ export type SignerEndpoints = [
|
|
|
117
119
|
},
|
|
118
120
|
{
|
|
119
121
|
Route: "/v1/auth";
|
|
120
|
-
Body: Omit<EmailAuthParams, "redirectParams"> & {
|
|
122
|
+
Body: Omit<EmailAuthParams, "redirectParams"> & {
|
|
123
|
+
redirectParams?: string;
|
|
124
|
+
};
|
|
121
125
|
Response: {
|
|
122
126
|
orgId: string;
|
|
123
127
|
otpId?: string;
|
|
@@ -177,3 +181,21 @@ export type GetWebAuthnAttestationResult = {
|
|
|
177
181
|
challenge: ArrayBuffer;
|
|
178
182
|
authenticatorUserId: ArrayBuffer;
|
|
179
183
|
};
|
|
184
|
+
|
|
185
|
+
export type OauthState = {
|
|
186
|
+
authProviderId: string;
|
|
187
|
+
isCustomProvider?: boolean;
|
|
188
|
+
requestKey: string;
|
|
189
|
+
turnkeyPublicKey: string;
|
|
190
|
+
expirationSeconds?: number;
|
|
191
|
+
redirectUrl?: string;
|
|
192
|
+
openerOrigin?: string;
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
export type GetOauthProviderUrlArgs = {
|
|
196
|
+
oauthParams: OauthParams;
|
|
197
|
+
turnkeyPublicKey: string;
|
|
198
|
+
oauthCallbackUrl: string;
|
|
199
|
+
oauthConfig?: OauthConfig;
|
|
200
|
+
usesRelativeUrl?: boolean;
|
|
201
|
+
};
|
package/src/errors.ts
CHANGED
|
@@ -18,6 +18,8 @@ export class NotAuthenticatedError extends BaseError {
|
|
|
18
18
|
export class OAuthProvidersError extends BaseError {
|
|
19
19
|
override name = "OAuthProvidersError";
|
|
20
20
|
constructor() {
|
|
21
|
-
super("OAuth providers not found", {
|
|
21
|
+
super("OAuth providers not found", {
|
|
22
|
+
docsPath: "/react/getting-started",
|
|
23
|
+
});
|
|
22
24
|
}
|
|
23
25
|
}
|
package/src/index.ts
CHANGED
package/src/oauth.ts
CHANGED
|
@@ -1,16 +1,5 @@
|
|
|
1
|
-
import { sha256 } from "viem";
|
|
2
1
|
import type { KnownAuthProvider } from "./signer";
|
|
3
2
|
|
|
4
|
-
/**
|
|
5
|
-
* Turnkey requires the nonce in the id token to be in this format.
|
|
6
|
-
*
|
|
7
|
-
* @param {string} turnkeyPublicKey key from a Turnkey iframe
|
|
8
|
-
* @returns {string} nonce to be used in OIDC
|
|
9
|
-
*/
|
|
10
|
-
export function getOauthNonce(turnkeyPublicKey: string): string {
|
|
11
|
-
return sha256(new TextEncoder().encode(turnkeyPublicKey)).slice(2);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
3
|
export type ScopeAndClaims = {
|
|
15
4
|
scope: string;
|
|
16
5
|
claims?: string;
|
|
@@ -34,3 +23,14 @@ export function getDefaultScopeAndClaims(
|
|
|
34
23
|
): ScopeAndClaims | undefined {
|
|
35
24
|
return DEFAULT_SCOPE_AND_CLAIMS[knownAuthProviderId];
|
|
36
25
|
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* "openid" is a required scope in the OIDC protocol. Insert it if the user
|
|
29
|
+
* forgot.
|
|
30
|
+
*
|
|
31
|
+
* @param {string} scope scope param which may be missing "openid"
|
|
32
|
+
* @returns {string} scope which most definitely contains "openid"
|
|
33
|
+
*/
|
|
34
|
+
export function addOpenIdIfAbsent(scope: string): string {
|
|
35
|
+
return scope.match(/\bopenid\b/) ? scope : `openid ${scope}`;
|
|
36
|
+
}
|
package/src/version.ts
CHANGED