@better-auth/core 1.7.0-beta.0 → 1.7.0-beta.10
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/api/index.d.mts +44 -1
- package/dist/api/index.mjs +69 -4
- package/dist/context/global.mjs +1 -1
- package/dist/context/transaction.d.mts +7 -4
- package/dist/context/transaction.mjs +6 -3
- package/dist/db/adapter/factory.mjs +91 -3
- package/dist/db/adapter/get-id-field.mjs +1 -1
- package/dist/db/adapter/index.d.mts +87 -3
- package/dist/db/adapter/types.d.mts +1 -1
- package/dist/db/get-tables.mjs +2 -1
- package/dist/db/type.d.mts +17 -0
- package/dist/env/env-impl.mjs +1 -1
- package/dist/error/codes.d.mts +1 -0
- package/dist/error/codes.mjs +1 -0
- package/dist/error/index.d.mts +7 -0
- package/dist/index.d.mts +2 -2
- package/dist/instrumentation/api.mjs +12 -0
- package/dist/instrumentation/noop.mjs +42 -0
- package/dist/instrumentation/pure.index.d.mts +7 -0
- package/dist/instrumentation/pure.index.mjs +7 -0
- package/dist/instrumentation/tracer.mjs +6 -3
- package/dist/oauth2/authorization-params.d.mts +12 -0
- package/dist/oauth2/authorization-params.mjs +12 -0
- package/dist/oauth2/basic-credentials.d.mts +30 -0
- package/dist/oauth2/basic-credentials.mjs +64 -0
- package/dist/oauth2/client-assertion.d.mts +38 -22
- package/dist/oauth2/client-assertion.mjs +63 -28
- package/dist/oauth2/client-credentials-token.d.mts +19 -40
- package/dist/oauth2/client-credentials-token.mjs +20 -31
- package/dist/oauth2/create-authorization-url.d.mts +11 -1
- package/dist/oauth2/create-authorization-url.mjs +27 -7
- package/dist/oauth2/dpop.d.mts +142 -0
- package/dist/oauth2/dpop.mjs +246 -0
- package/dist/oauth2/index.d.mts +14 -9
- package/dist/oauth2/index.mjs +12 -8
- package/dist/oauth2/oauth-provider.d.mts +150 -10
- package/dist/oauth2/refresh-access-token.d.mts +20 -40
- package/dist/oauth2/refresh-access-token.mjs +38 -36
- package/dist/oauth2/reject-redirects.mjs +65 -0
- package/dist/oauth2/token-endpoint-auth.d.mts +17 -0
- package/dist/oauth2/token-endpoint-auth.mjs +89 -0
- package/dist/oauth2/utils.d.mts +23 -1
- package/dist/oauth2/utils.mjs +48 -2
- package/dist/oauth2/validate-authorization-code.d.mts +17 -52
- package/dist/oauth2/validate-authorization-code.mjs +28 -34
- package/dist/oauth2/verify-id-token.d.mts +27 -0
- package/dist/oauth2/verify-id-token.mjs +62 -0
- package/dist/oauth2/verify.d.mts +88 -15
- package/dist/oauth2/verify.mjs +203 -25
- package/dist/social-providers/apple.d.mts +16 -4
- package/dist/social-providers/apple.mjs +17 -24
- package/dist/social-providers/atlassian.d.mts +5 -1
- package/dist/social-providers/atlassian.mjs +6 -3
- package/dist/social-providers/cognito.d.mts +27 -3
- package/dist/social-providers/cognito.mjs +15 -25
- package/dist/social-providers/discord.d.mts +7 -3
- package/dist/social-providers/discord.mjs +16 -3
- package/dist/social-providers/dropbox.d.mts +5 -1
- package/dist/social-providers/dropbox.mjs +5 -4
- package/dist/social-providers/facebook.d.mts +24 -5
- package/dist/social-providers/facebook.mjs +54 -20
- package/dist/social-providers/figma.d.mts +5 -1
- package/dist/social-providers/figma.mjs +4 -3
- package/dist/social-providers/github.d.mts +6 -2
- package/dist/social-providers/github.mjs +5 -4
- package/dist/social-providers/gitlab.d.mts +5 -1
- package/dist/social-providers/gitlab.mjs +3 -2
- package/dist/social-providers/google.d.mts +53 -5
- package/dist/social-providers/google.mjs +69 -25
- package/dist/social-providers/huggingface.d.mts +5 -1
- package/dist/social-providers/huggingface.mjs +3 -2
- package/dist/social-providers/index.d.mts +221 -45
- package/dist/social-providers/index.mjs +2 -2
- package/dist/social-providers/kakao.d.mts +5 -1
- package/dist/social-providers/kakao.mjs +3 -2
- package/dist/social-providers/kick.d.mts +5 -1
- package/dist/social-providers/kick.mjs +3 -2
- package/dist/social-providers/line.d.mts +8 -2
- package/dist/social-providers/line.mjs +5 -6
- package/dist/social-providers/linear.d.mts +5 -1
- package/dist/social-providers/linear.mjs +3 -2
- package/dist/social-providers/linkedin.d.mts +7 -3
- package/dist/social-providers/linkedin.mjs +4 -3
- package/dist/social-providers/microsoft-entra-id.d.mts +41 -7
- package/dist/social-providers/microsoft-entra-id.mjs +37 -28
- package/dist/social-providers/naver.d.mts +5 -1
- package/dist/social-providers/naver.mjs +3 -2
- package/dist/social-providers/notion.d.mts +5 -1
- package/dist/social-providers/notion.mjs +5 -2
- package/dist/social-providers/paybin.d.mts +5 -1
- package/dist/social-providers/paybin.mjs +4 -3
- package/dist/social-providers/paypal.d.mts +6 -2
- package/dist/social-providers/paypal.mjs +19 -14
- package/dist/social-providers/polar.d.mts +5 -1
- package/dist/social-providers/polar.mjs +3 -2
- package/dist/social-providers/railway.d.mts +5 -1
- package/dist/social-providers/railway.mjs +3 -2
- package/dist/social-providers/reddit.d.mts +5 -1
- package/dist/social-providers/reddit.mjs +7 -5
- package/dist/social-providers/roblox.d.mts +6 -2
- package/dist/social-providers/roblox.mjs +12 -2
- package/dist/social-providers/salesforce.d.mts +5 -1
- package/dist/social-providers/salesforce.mjs +4 -3
- package/dist/social-providers/slack.d.mts +6 -2
- package/dist/social-providers/slack.mjs +11 -8
- package/dist/social-providers/spotify.d.mts +5 -1
- package/dist/social-providers/spotify.mjs +3 -2
- package/dist/social-providers/tiktok.d.mts +5 -1
- package/dist/social-providers/tiktok.mjs +14 -2
- package/dist/social-providers/twitch.d.mts +5 -1
- package/dist/social-providers/twitch.mjs +3 -2
- package/dist/social-providers/twitter.d.mts +4 -1
- package/dist/social-providers/twitter.mjs +2 -1
- package/dist/social-providers/vercel.d.mts +5 -1
- package/dist/social-providers/vercel.mjs +3 -2
- package/dist/social-providers/vk.d.mts +5 -1
- package/dist/social-providers/vk.mjs +3 -2
- package/dist/social-providers/wechat.d.mts +5 -1
- package/dist/social-providers/wechat.mjs +8 -2
- package/dist/social-providers/zoom.d.mts +5 -1
- package/dist/social-providers/zoom.mjs +10 -17
- package/dist/types/context.d.mts +55 -6
- package/dist/types/index.d.mts +1 -1
- package/dist/types/init-options.d.mts +182 -12
- package/dist/types/plugin-client.d.mts +12 -2
- package/dist/utils/async.d.mts +22 -0
- package/dist/utils/async.mjs +32 -0
- package/dist/utils/host.d.mts +147 -0
- package/dist/utils/host.mjs +298 -0
- package/dist/utils/ip.d.mts +28 -5
- package/dist/utils/ip.mjs +118 -4
- package/dist/utils/is-api-error.d.mts +6 -0
- package/dist/utils/is-api-error.mjs +8 -0
- package/dist/utils/redirect-uri.d.mts +20 -0
- package/dist/utils/redirect-uri.mjs +48 -0
- package/dist/utils/string.d.mts +5 -1
- package/dist/utils/string.mjs +20 -1
- package/dist/utils/url.d.mts +18 -1
- package/dist/utils/url.mjs +34 -4
- package/package.json +26 -16
- package/src/api/index.ts +121 -5
- package/src/context/transaction.ts +45 -12
- package/src/db/adapter/factory.ts +193 -7
- package/src/db/adapter/get-id-field.ts +2 -2
- package/src/db/adapter/index.ts +85 -2
- package/src/db/adapter/types.ts +2 -0
- package/src/db/get-tables.ts +9 -1
- package/src/db/schema/account.ts +4 -1
- package/src/db/schema/user.ts +3 -0
- package/src/db/type.ts +17 -0
- package/src/env/env-impl.ts +1 -2
- package/src/error/codes.ts +1 -0
- package/src/error/index.ts +9 -0
- package/src/instrumentation/api.ts +17 -0
- package/src/instrumentation/noop.ts +74 -0
- package/src/instrumentation/pure.index.ts +31 -0
- package/src/instrumentation/tracer.ts +8 -3
- package/src/oauth2/authorization-params.ts +28 -0
- package/src/oauth2/basic-credentials.ts +87 -0
- package/src/oauth2/client-assertion.ts +131 -58
- package/src/oauth2/client-credentials-token.ts +50 -74
- package/src/oauth2/create-authorization-url.ts +33 -7
- package/src/oauth2/dpop.ts +568 -0
- package/src/oauth2/index.ts +81 -11
- package/src/oauth2/oauth-provider.ts +159 -11
- package/src/oauth2/refresh-access-token.ts +82 -83
- package/src/oauth2/reject-redirects.ts +75 -0
- package/src/oauth2/token-endpoint-auth.ts +221 -0
- package/src/oauth2/utils.ts +72 -5
- package/src/oauth2/validate-authorization-code.ts +69 -89
- package/src/oauth2/verify-id-token.ts +115 -0
- package/src/oauth2/verify.ts +409 -78
- package/src/social-providers/apple.ts +30 -40
- package/src/social-providers/atlassian.ts +8 -1
- package/src/social-providers/cognito.ts +36 -39
- package/src/social-providers/discord.ts +22 -18
- package/src/social-providers/dropbox.ts +7 -5
- package/src/social-providers/facebook.ts +108 -52
- package/src/social-providers/figma.ts +8 -1
- package/src/social-providers/github.ts +5 -3
- package/src/social-providers/gitlab.ts +2 -0
- package/src/social-providers/google.ts +141 -39
- package/src/social-providers/huggingface.ts +8 -1
- package/src/social-providers/kakao.ts +2 -1
- package/src/social-providers/kick.ts +8 -1
- package/src/social-providers/line.ts +25 -27
- package/src/social-providers/linear.ts +8 -1
- package/src/social-providers/linkedin.ts +5 -3
- package/src/social-providers/microsoft-entra-id.ts +100 -55
- package/src/social-providers/naver.ts +2 -1
- package/src/social-providers/notion.ts +8 -1
- package/src/social-providers/paybin.ts +2 -0
- package/src/social-providers/paypal.ts +28 -17
- package/src/social-providers/polar.ts +8 -1
- package/src/social-providers/railway.ts +8 -1
- package/src/social-providers/reddit.ts +9 -4
- package/src/social-providers/roblox.ts +16 -11
- package/src/social-providers/salesforce.ts +8 -1
- package/src/social-providers/slack.ts +15 -9
- package/src/social-providers/spotify.ts +8 -1
- package/src/social-providers/tiktok.ts +22 -9
- package/src/social-providers/twitch.ts +2 -1
- package/src/social-providers/twitter.ts +1 -0
- package/src/social-providers/vercel.ts +8 -1
- package/src/social-providers/vk.ts +8 -1
- package/src/social-providers/wechat.ts +17 -2
- package/src/social-providers/zoom.ts +15 -19
- package/src/types/context.ts +57 -5
- package/src/types/index.ts +7 -0
- package/src/types/init-options.ts +204 -14
- package/src/types/plugin-client.ts +16 -2
- package/src/utils/async.ts +53 -0
- package/src/utils/host.ts +425 -0
- package/src/utils/ip.ts +197 -13
- package/src/utils/is-api-error.ts +10 -0
- package/src/utils/redirect-uri.ts +54 -0
- package/src/utils/string.ts +37 -0
- package/src/utils/url.ts +38 -4
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { APIError } from "../error/index.mjs";
|
|
1
|
+
import { APIError, BetterAuthError } from "../error/index.mjs";
|
|
2
|
+
import { logger } from "../env/logger.mjs";
|
|
3
|
+
import { getPrimaryClientId } from "../oauth2/utils.mjs";
|
|
2
4
|
import { createAuthorizationURL } from "../oauth2/create-authorization-url.mjs";
|
|
3
5
|
import { refreshAccessToken } from "../oauth2/refresh-access-token.mjs";
|
|
4
6
|
import { validateAuthorizationCode } from "../oauth2/validate-authorization-code.mjs";
|
|
5
|
-
import { decodeJwt,
|
|
7
|
+
import { decodeJwt, importJWK } from "jose";
|
|
6
8
|
import { betterFetch } from "@better-fetch/fetch";
|
|
7
9
|
//#region src/social-providers/apple.ts
|
|
8
10
|
const apple = (options) => {
|
|
@@ -10,7 +12,11 @@ const apple = (options) => {
|
|
|
10
12
|
return {
|
|
11
13
|
id: "apple",
|
|
12
14
|
name: "Apple",
|
|
13
|
-
async createAuthorizationURL({ state, scopes, redirectURI }) {
|
|
15
|
+
async createAuthorizationURL({ state, scopes, redirectURI, additionalParams }) {
|
|
16
|
+
if (!getPrimaryClientId(options.clientId) || !options.clientSecret) {
|
|
17
|
+
logger.error("Client ID and client secret are required for Apple. Make sure to provide them in the options.");
|
|
18
|
+
throw new BetterAuthError("CLIENT_ID_AND_SECRET_REQUIRED");
|
|
19
|
+
}
|
|
14
20
|
const _scope = options.disableDefaultScope ? [] : ["email", "name"];
|
|
15
21
|
if (options.scope) _scope.push(...options.scope);
|
|
16
22
|
if (scopes) _scope.push(...scopes);
|
|
@@ -22,7 +28,8 @@ const apple = (options) => {
|
|
|
22
28
|
state,
|
|
23
29
|
redirectURI,
|
|
24
30
|
responseMode: "form_post",
|
|
25
|
-
responseType: "code id_token"
|
|
31
|
+
responseType: "code id_token",
|
|
32
|
+
additionalParams
|
|
26
33
|
});
|
|
27
34
|
},
|
|
28
35
|
validateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {
|
|
@@ -34,26 +41,12 @@ const apple = (options) => {
|
|
|
34
41
|
tokenEndpoint
|
|
35
42
|
});
|
|
36
43
|
},
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
const { payload: jwtClaims } = await jwtVerify(token, await getApplePublicKey(kid), {
|
|
44
|
-
algorithms: [jwtAlg],
|
|
45
|
-
issuer: "https://appleid.apple.com",
|
|
46
|
-
audience: options.audience && options.audience.length ? options.audience : options.appBundleIdentifier ? options.appBundleIdentifier : options.clientId,
|
|
47
|
-
maxTokenAge: "1h"
|
|
48
|
-
});
|
|
49
|
-
["email_verified", "is_private_email"].forEach((field) => {
|
|
50
|
-
if (jwtClaims[field] !== void 0) jwtClaims[field] = Boolean(jwtClaims[field]);
|
|
51
|
-
});
|
|
52
|
-
if (nonce && jwtClaims.nonce !== nonce) return false;
|
|
53
|
-
return !!jwtClaims;
|
|
54
|
-
} catch {
|
|
55
|
-
return false;
|
|
56
|
-
}
|
|
44
|
+
idToken: {
|
|
45
|
+
jwks: (header) => getApplePublicKey(header.kid),
|
|
46
|
+
issuer: "https://appleid.apple.com",
|
|
47
|
+
audience: options.audience && options.audience.length ? options.audience : options.appBundleIdentifier ? options.appBundleIdentifier : options.clientId,
|
|
48
|
+
maxTokenAge: "1h",
|
|
49
|
+
nonceComparison: "exact-or-sha256"
|
|
57
50
|
},
|
|
58
51
|
refreshAccessToken: options.refreshAccessToken ? options.refreshAccessToken : async (refreshToken) => {
|
|
59
52
|
return refreshAccessToken({
|
|
@@ -25,7 +25,8 @@ declare const atlassian: (options: AtlassianOptions) => {
|
|
|
25
25
|
state,
|
|
26
26
|
scopes,
|
|
27
27
|
codeVerifier,
|
|
28
|
-
redirectURI
|
|
28
|
+
redirectURI,
|
|
29
|
+
additionalParams
|
|
29
30
|
}: {
|
|
30
31
|
state: string;
|
|
31
32
|
codeVerifier: string;
|
|
@@ -33,6 +34,8 @@ declare const atlassian: (options: AtlassianOptions) => {
|
|
|
33
34
|
redirectURI: string;
|
|
34
35
|
display?: string | undefined;
|
|
35
36
|
loginHint?: string | undefined;
|
|
37
|
+
idTokenNonce?: string | undefined;
|
|
38
|
+
additionalParams?: Record<string, string> | undefined;
|
|
36
39
|
}): Promise<URL>;
|
|
37
40
|
validateAuthorizationCode: ({
|
|
38
41
|
code,
|
|
@@ -46,6 +49,7 @@ declare const atlassian: (options: AtlassianOptions) => {
|
|
|
46
49
|
}) => Promise<OAuth2Tokens>;
|
|
47
50
|
refreshAccessToken: (refreshToken: string) => Promise<OAuth2Tokens>;
|
|
48
51
|
getUserInfo(token: OAuth2Tokens & {
|
|
52
|
+
expectedIdTokenNonce?: string | undefined;
|
|
49
53
|
user?: {
|
|
50
54
|
name?: {
|
|
51
55
|
firstName?: string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { logger } from "../env/logger.mjs";
|
|
2
1
|
import { BetterAuthError } from "../error/index.mjs";
|
|
2
|
+
import { logger } from "../env/logger.mjs";
|
|
3
3
|
import { createAuthorizationURL } from "../oauth2/create-authorization-url.mjs";
|
|
4
4
|
import { refreshAccessToken } from "../oauth2/refresh-access-token.mjs";
|
|
5
5
|
import { validateAuthorizationCode } from "../oauth2/validate-authorization-code.mjs";
|
|
@@ -10,7 +10,7 @@ const atlassian = (options) => {
|
|
|
10
10
|
return {
|
|
11
11
|
id: "atlassian",
|
|
12
12
|
name: "Atlassian",
|
|
13
|
-
async createAuthorizationURL({ state, scopes, codeVerifier, redirectURI }) {
|
|
13
|
+
async createAuthorizationURL({ state, scopes, codeVerifier, redirectURI, additionalParams }) {
|
|
14
14
|
if (!options.clientId || !options.clientSecret) {
|
|
15
15
|
logger.error("Client Id and Secret are required for Atlassian");
|
|
16
16
|
throw new BetterAuthError("CLIENT_ID_AND_SECRET_REQUIRED");
|
|
@@ -27,7 +27,10 @@ const atlassian = (options) => {
|
|
|
27
27
|
state,
|
|
28
28
|
codeVerifier,
|
|
29
29
|
redirectURI,
|
|
30
|
-
additionalParams: {
|
|
30
|
+
additionalParams: {
|
|
31
|
+
...additionalParams ?? {},
|
|
32
|
+
audience: "api.atlassian.com"
|
|
33
|
+
},
|
|
31
34
|
prompt: options.prompt
|
|
32
35
|
});
|
|
33
36
|
},
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { OAuth2Tokens, ProviderOptions } from "../oauth2/oauth-provider.mjs";
|
|
2
|
+
import * as jose from "jose";
|
|
3
|
+
|
|
2
4
|
//#region src/social-providers/cognito.d.ts
|
|
3
5
|
interface CognitoProfile {
|
|
4
6
|
sub: string;
|
|
@@ -19,7 +21,7 @@ interface CognitoProfile {
|
|
|
19
21
|
[key: string]: any;
|
|
20
22
|
}
|
|
21
23
|
interface CognitoOptions extends ProviderOptions<CognitoProfile> {
|
|
22
|
-
clientId: string;
|
|
24
|
+
clientId: string | string[];
|
|
23
25
|
/**
|
|
24
26
|
* The Cognito domain (e.g., "your-app.auth.us-east-1.amazoncognito.com")
|
|
25
27
|
*/
|
|
@@ -30,6 +32,19 @@ interface CognitoOptions extends ProviderOptions<CognitoProfile> {
|
|
|
30
32
|
region: string;
|
|
31
33
|
userPoolId: string;
|
|
32
34
|
requireClientSecret?: boolean | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* Skip the Cognito hosted-UI identity-provider picker by preselecting an
|
|
37
|
+
* IdP (maps to the `identity_provider` query parameter on the authorize
|
|
38
|
+
* request). Accepts `"COGNITO"`, a SAML/OIDC provider name configured on
|
|
39
|
+
* the User Pool, or one of the social providers (`"Google"`, `"Facebook"`,
|
|
40
|
+
* `"LoginWithAmazon"`, `"SignInWithApple"`).
|
|
41
|
+
*
|
|
42
|
+
* Per-request overrides via `signIn.social({ additionalParams: { identity_provider } })`
|
|
43
|
+
* take precedence over this value.
|
|
44
|
+
*
|
|
45
|
+
* @see https://docs.aws.amazon.com/cognito/latest/developerguide/authorization-endpoint.html
|
|
46
|
+
*/
|
|
47
|
+
identityProvider?: string | undefined;
|
|
33
48
|
}
|
|
34
49
|
declare const cognito: (options: CognitoOptions) => {
|
|
35
50
|
id: "cognito";
|
|
@@ -38,7 +53,8 @@ declare const cognito: (options: CognitoOptions) => {
|
|
|
38
53
|
state,
|
|
39
54
|
scopes,
|
|
40
55
|
codeVerifier,
|
|
41
|
-
redirectURI
|
|
56
|
+
redirectURI,
|
|
57
|
+
additionalParams
|
|
42
58
|
}: {
|
|
43
59
|
state: string;
|
|
44
60
|
codeVerifier: string;
|
|
@@ -46,6 +62,8 @@ declare const cognito: (options: CognitoOptions) => {
|
|
|
46
62
|
redirectURI: string;
|
|
47
63
|
display?: string | undefined;
|
|
48
64
|
loginHint?: string | undefined;
|
|
65
|
+
idTokenNonce?: string | undefined;
|
|
66
|
+
additionalParams?: Record<string, string> | undefined;
|
|
49
67
|
}): Promise<URL>;
|
|
50
68
|
validateAuthorizationCode: ({
|
|
51
69
|
code,
|
|
@@ -58,8 +76,14 @@ declare const cognito: (options: CognitoOptions) => {
|
|
|
58
76
|
deviceId?: string | undefined;
|
|
59
77
|
}) => Promise<OAuth2Tokens>;
|
|
60
78
|
refreshAccessToken: (refreshToken: string) => Promise<OAuth2Tokens>;
|
|
61
|
-
|
|
79
|
+
idToken: {
|
|
80
|
+
jwks: (header: jose.JWTHeaderParameters) => Promise<Uint8Array<ArrayBufferLike> | CryptoKey>;
|
|
81
|
+
issuer: string;
|
|
82
|
+
audience: string | string[];
|
|
83
|
+
maxTokenAge: string;
|
|
84
|
+
};
|
|
62
85
|
getUserInfo(token: OAuth2Tokens & {
|
|
86
|
+
expectedIdTokenNonce?: string | undefined;
|
|
63
87
|
user?: {
|
|
64
88
|
name?: {
|
|
65
89
|
firstName?: string;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { logger } from "../env/logger.mjs";
|
|
2
1
|
import { APIError, BetterAuthError } from "../error/index.mjs";
|
|
2
|
+
import { logger } from "../env/logger.mjs";
|
|
3
|
+
import { getPrimaryClientId } from "../oauth2/utils.mjs";
|
|
3
4
|
import { createAuthorizationURL } from "../oauth2/create-authorization-url.mjs";
|
|
4
5
|
import { refreshAccessToken } from "../oauth2/refresh-access-token.mjs";
|
|
5
6
|
import { validateAuthorizationCode } from "../oauth2/validate-authorization-code.mjs";
|
|
6
|
-
import { decodeJwt,
|
|
7
|
+
import { decodeJwt, importJWK } from "jose";
|
|
7
8
|
import { betterFetch } from "@better-fetch/fetch";
|
|
8
9
|
//#region src/social-providers/cognito.ts
|
|
9
10
|
const cognito = (options) => {
|
|
@@ -18,8 +19,8 @@ const cognito = (options) => {
|
|
|
18
19
|
return {
|
|
19
20
|
id: "cognito",
|
|
20
21
|
name: "Cognito",
|
|
21
|
-
async createAuthorizationURL({ state, scopes, codeVerifier, redirectURI }) {
|
|
22
|
-
if (!options.clientId) {
|
|
22
|
+
async createAuthorizationURL({ state, scopes, codeVerifier, redirectURI, additionalParams }) {
|
|
23
|
+
if (!getPrimaryClientId(options.clientId)) {
|
|
23
24
|
logger.error("ClientId is required for Amazon Cognito. Make sure to provide them in the options.");
|
|
24
25
|
throw new BetterAuthError("CLIENT_ID_AND_SECRET_REQUIRED");
|
|
25
26
|
}
|
|
@@ -42,7 +43,11 @@ const cognito = (options) => {
|
|
|
42
43
|
state,
|
|
43
44
|
codeVerifier,
|
|
44
45
|
redirectURI,
|
|
45
|
-
prompt: options.prompt
|
|
46
|
+
prompt: options.prompt,
|
|
47
|
+
additionalParams: {
|
|
48
|
+
...options.identityProvider ? { identity_provider: options.identityProvider } : {},
|
|
49
|
+
...additionalParams ?? {}
|
|
50
|
+
}
|
|
46
51
|
});
|
|
47
52
|
const scopeValue = url.searchParams.get("scope");
|
|
48
53
|
if (scopeValue) {
|
|
@@ -74,26 +79,11 @@ const cognito = (options) => {
|
|
|
74
79
|
tokenEndpoint
|
|
75
80
|
});
|
|
76
81
|
},
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
if (!kid || !jwtAlg) return false;
|
|
83
|
-
const publicKey = await getCognitoPublicKey(kid, options.region, options.userPoolId);
|
|
84
|
-
const expectedIssuer = `https://cognito-idp.${options.region}.amazonaws.com/${options.userPoolId}`;
|
|
85
|
-
const { payload: jwtClaims } = await jwtVerify(token, publicKey, {
|
|
86
|
-
algorithms: [jwtAlg],
|
|
87
|
-
issuer: expectedIssuer,
|
|
88
|
-
audience: options.clientId,
|
|
89
|
-
maxTokenAge: "1h"
|
|
90
|
-
});
|
|
91
|
-
if (nonce && jwtClaims.nonce !== nonce) return false;
|
|
92
|
-
return true;
|
|
93
|
-
} catch (error) {
|
|
94
|
-
logger.error("Failed to verify ID token:", error);
|
|
95
|
-
return false;
|
|
96
|
-
}
|
|
82
|
+
idToken: {
|
|
83
|
+
jwks: (header) => getCognitoPublicKey(header.kid, options.region, options.userPoolId),
|
|
84
|
+
issuer: `https://cognito-idp.${options.region}.amazonaws.com/${options.userPoolId}`,
|
|
85
|
+
audience: options.clientId,
|
|
86
|
+
maxTokenAge: "1h"
|
|
97
87
|
},
|
|
98
88
|
async getUserInfo(token) {
|
|
99
89
|
if (options.getUserInfo) return options.getUserInfo(token);
|
|
@@ -38,7 +38,7 @@ interface DiscordProfile extends Record<string, any> {
|
|
|
38
38
|
/** whether the email on this account has been verified */
|
|
39
39
|
verified: boolean;
|
|
40
40
|
/** the user's email */
|
|
41
|
-
email
|
|
41
|
+
email?: string | null;
|
|
42
42
|
/**
|
|
43
43
|
* the flags on a user's account:
|
|
44
44
|
* https://discord.com/developers/docs/resources/user#user-object-user-flags
|
|
@@ -80,7 +80,8 @@ declare const discord: (options: DiscordOptions) => {
|
|
|
80
80
|
createAuthorizationURL({
|
|
81
81
|
state,
|
|
82
82
|
scopes,
|
|
83
|
-
redirectURI
|
|
83
|
+
redirectURI,
|
|
84
|
+
additionalParams
|
|
84
85
|
}: {
|
|
85
86
|
state: string;
|
|
86
87
|
codeVerifier: string;
|
|
@@ -88,7 +89,9 @@ declare const discord: (options: DiscordOptions) => {
|
|
|
88
89
|
redirectURI: string;
|
|
89
90
|
display?: string | undefined;
|
|
90
91
|
loginHint?: string | undefined;
|
|
91
|
-
|
|
92
|
+
idTokenNonce?: string | undefined;
|
|
93
|
+
additionalParams?: Record<string, string> | undefined;
|
|
94
|
+
}): Promise<URL>;
|
|
92
95
|
validateAuthorizationCode: ({
|
|
93
96
|
code,
|
|
94
97
|
redirectURI
|
|
@@ -100,6 +103,7 @@ declare const discord: (options: DiscordOptions) => {
|
|
|
100
103
|
}) => Promise<OAuth2Tokens>;
|
|
101
104
|
refreshAccessToken: (refreshToken: string) => Promise<OAuth2Tokens>;
|
|
102
105
|
getUserInfo(token: OAuth2Tokens & {
|
|
106
|
+
expectedIdTokenNonce?: string | undefined;
|
|
103
107
|
user?: {
|
|
104
108
|
name?: {
|
|
105
109
|
firstName?: string;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createAuthorizationURL } from "../oauth2/create-authorization-url.mjs";
|
|
1
2
|
import { refreshAccessToken } from "../oauth2/refresh-access-token.mjs";
|
|
2
3
|
import { validateAuthorizationCode } from "../oauth2/validate-authorization-code.mjs";
|
|
3
4
|
import { betterFetch } from "@better-fetch/fetch";
|
|
@@ -7,12 +8,24 @@ const discord = (options) => {
|
|
|
7
8
|
return {
|
|
8
9
|
id: "discord",
|
|
9
10
|
name: "Discord",
|
|
10
|
-
createAuthorizationURL({ state, scopes, redirectURI }) {
|
|
11
|
+
createAuthorizationURL({ state, scopes, redirectURI, additionalParams }) {
|
|
11
12
|
const _scopes = options.disableDefaultScope ? [] : ["identify", "email"];
|
|
12
13
|
if (scopes) _scopes.push(...scopes);
|
|
13
14
|
if (options.scope) _scopes.push(...options.scope);
|
|
14
|
-
const
|
|
15
|
-
return
|
|
15
|
+
const hasBotScope = _scopes.includes("bot");
|
|
16
|
+
return createAuthorizationURL({
|
|
17
|
+
id: "discord",
|
|
18
|
+
options,
|
|
19
|
+
authorizationEndpoint: "https://discord.com/api/oauth2/authorize",
|
|
20
|
+
scopes: _scopes,
|
|
21
|
+
state,
|
|
22
|
+
redirectURI,
|
|
23
|
+
prompt: options.prompt || "none",
|
|
24
|
+
additionalParams: {
|
|
25
|
+
...hasBotScope && options.permissions !== void 0 ? { permissions: String(options.permissions) } : {},
|
|
26
|
+
...additionalParams ?? {}
|
|
27
|
+
}
|
|
28
|
+
});
|
|
16
29
|
},
|
|
17
30
|
validateAuthorizationCode: async ({ code, redirectURI }) => {
|
|
18
31
|
return validateAuthorizationCode({
|
|
@@ -24,7 +24,8 @@ declare const dropbox: (options: DropboxOptions) => {
|
|
|
24
24
|
state,
|
|
25
25
|
scopes,
|
|
26
26
|
codeVerifier,
|
|
27
|
-
redirectURI
|
|
27
|
+
redirectURI,
|
|
28
|
+
additionalParams
|
|
28
29
|
}: {
|
|
29
30
|
state: string;
|
|
30
31
|
codeVerifier: string;
|
|
@@ -32,6 +33,8 @@ declare const dropbox: (options: DropboxOptions) => {
|
|
|
32
33
|
redirectURI: string;
|
|
33
34
|
display?: string | undefined;
|
|
34
35
|
loginHint?: string | undefined;
|
|
36
|
+
idTokenNonce?: string | undefined;
|
|
37
|
+
additionalParams?: Record<string, string> | undefined;
|
|
35
38
|
}) => Promise<URL>;
|
|
36
39
|
validateAuthorizationCode: ({
|
|
37
40
|
code,
|
|
@@ -45,6 +48,7 @@ declare const dropbox: (options: DropboxOptions) => {
|
|
|
45
48
|
}) => Promise<OAuth2Tokens>;
|
|
46
49
|
refreshAccessToken: (refreshToken: string) => Promise<OAuth2Tokens>;
|
|
47
50
|
getUserInfo(token: OAuth2Tokens & {
|
|
51
|
+
expectedIdTokenNonce?: string | undefined;
|
|
48
52
|
user?: {
|
|
49
53
|
name?: {
|
|
50
54
|
firstName?: string;
|
|
@@ -8,12 +8,10 @@ const dropbox = (options) => {
|
|
|
8
8
|
return {
|
|
9
9
|
id: "dropbox",
|
|
10
10
|
name: "Dropbox",
|
|
11
|
-
createAuthorizationURL: async ({ state, scopes, codeVerifier, redirectURI }) => {
|
|
11
|
+
createAuthorizationURL: async ({ state, scopes, codeVerifier, redirectURI, additionalParams }) => {
|
|
12
12
|
const _scopes = options.disableDefaultScope ? [] : ["account_info.read"];
|
|
13
13
|
if (options.scope) _scopes.push(...options.scope);
|
|
14
14
|
if (scopes) _scopes.push(...scopes);
|
|
15
|
-
const additionalParams = {};
|
|
16
|
-
if (options.accessType) additionalParams.token_access_type = options.accessType;
|
|
17
15
|
return await createAuthorizationURL({
|
|
18
16
|
id: "dropbox",
|
|
19
17
|
options,
|
|
@@ -22,7 +20,10 @@ const dropbox = (options) => {
|
|
|
22
20
|
state,
|
|
23
21
|
redirectURI,
|
|
24
22
|
codeVerifier,
|
|
25
|
-
additionalParams
|
|
23
|
+
additionalParams: {
|
|
24
|
+
...options.accessType ? { token_access_type: options.accessType } : {},
|
|
25
|
+
...additionalParams ?? {}
|
|
26
|
+
}
|
|
26
27
|
});
|
|
27
28
|
},
|
|
28
29
|
validateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { OAuth2Tokens, ProviderOptions } from "../oauth2/oauth-provider.mjs";
|
|
2
|
+
import * as jose from "jose";
|
|
3
|
+
|
|
2
4
|
//#region src/social-providers/facebook.d.ts
|
|
3
5
|
interface FacebookProfile {
|
|
4
6
|
id: string;
|
|
5
7
|
name: string;
|
|
6
|
-
email
|
|
7
|
-
email_verified
|
|
8
|
+
email?: string;
|
|
9
|
+
email_verified?: boolean;
|
|
8
10
|
picture: {
|
|
9
11
|
data: {
|
|
10
12
|
height: number;
|
|
@@ -15,7 +17,7 @@ interface FacebookProfile {
|
|
|
15
17
|
};
|
|
16
18
|
}
|
|
17
19
|
interface FacebookOptions extends ProviderOptions<FacebookProfile> {
|
|
18
|
-
clientId: string;
|
|
20
|
+
clientId: string | string[];
|
|
19
21
|
/**
|
|
20
22
|
* Extend list of fields to retrieve from the Facebook user profile.
|
|
21
23
|
*
|
|
@@ -34,7 +36,8 @@ declare const facebook: (options: FacebookOptions) => {
|
|
|
34
36
|
state,
|
|
35
37
|
scopes,
|
|
36
38
|
redirectURI,
|
|
37
|
-
loginHint
|
|
39
|
+
loginHint,
|
|
40
|
+
additionalParams
|
|
38
41
|
}: {
|
|
39
42
|
state: string;
|
|
40
43
|
codeVerifier: string;
|
|
@@ -42,6 +45,8 @@ declare const facebook: (options: FacebookOptions) => {
|
|
|
42
45
|
redirectURI: string;
|
|
43
46
|
display?: string | undefined;
|
|
44
47
|
loginHint?: string | undefined;
|
|
48
|
+
idTokenNonce?: string | undefined;
|
|
49
|
+
additionalParams?: Record<string, string> | undefined;
|
|
45
50
|
}): Promise<URL>;
|
|
46
51
|
validateAuthorizationCode: ({
|
|
47
52
|
code,
|
|
@@ -52,9 +57,23 @@ declare const facebook: (options: FacebookOptions) => {
|
|
|
52
57
|
codeVerifier?: string | undefined;
|
|
53
58
|
deviceId?: string | undefined;
|
|
54
59
|
}) => Promise<OAuth2Tokens>;
|
|
55
|
-
|
|
60
|
+
idToken: {
|
|
61
|
+
jwks: {
|
|
62
|
+
(protectedHeader?: jose.JWSHeaderParameters, token?: jose.FlattenedJWSInput): Promise<jose.CryptoKey>;
|
|
63
|
+
coolingDown: boolean;
|
|
64
|
+
fresh: boolean;
|
|
65
|
+
reloading: boolean;
|
|
66
|
+
reload: () => Promise<void>;
|
|
67
|
+
jwks: () => jose.JSONWebKeySet | undefined;
|
|
68
|
+
};
|
|
69
|
+
issuer: string;
|
|
70
|
+
audience: string | string[];
|
|
71
|
+
algorithms: string[];
|
|
72
|
+
allowOpaqueToken: true;
|
|
73
|
+
};
|
|
56
74
|
refreshAccessToken: (refreshToken: string) => Promise<OAuth2Tokens>;
|
|
57
75
|
getUserInfo(token: OAuth2Tokens & {
|
|
76
|
+
expectedIdTokenNonce?: string | undefined;
|
|
58
77
|
user?: {
|
|
59
78
|
name?: {
|
|
60
79
|
firstName?: string;
|
|
@@ -1,14 +1,49 @@
|
|
|
1
|
+
import { BetterAuthError } from "../error/index.mjs";
|
|
2
|
+
import { logger } from "../env/logger.mjs";
|
|
3
|
+
import { getPrimaryClientId } from "../oauth2/utils.mjs";
|
|
1
4
|
import { createAuthorizationURL } from "../oauth2/create-authorization-url.mjs";
|
|
2
5
|
import { refreshAccessToken } from "../oauth2/refresh-access-token.mjs";
|
|
3
6
|
import { validateAuthorizationCode } from "../oauth2/validate-authorization-code.mjs";
|
|
4
|
-
import { createRemoteJWKSet, decodeJwt
|
|
7
|
+
import { createRemoteJWKSet, decodeJwt } from "jose";
|
|
5
8
|
import { betterFetch } from "@better-fetch/fetch";
|
|
6
9
|
//#region src/social-providers/facebook.ts
|
|
10
|
+
/**
|
|
11
|
+
* Validate an opaque Facebook access token against the configured app.
|
|
12
|
+
*
|
|
13
|
+
* Facebook access tokens are not audience-bound at the Graph `/me` endpoint: a
|
|
14
|
+
* token minted for any Facebook app returns that app's profile. Without this
|
|
15
|
+
* check, a token issued to an unrelated app could be presented to this
|
|
16
|
+
* app's direct sign-in path and accepted as proof of identity. We call the
|
|
17
|
+
* `debug_token` endpoint and require the token to be valid, bound to one of the
|
|
18
|
+
* configured client ids, and tied to a user.
|
|
19
|
+
*
|
|
20
|
+
* @see https://developers.facebook.com/docs/facebook-login/guides/access-tokens/debugging
|
|
21
|
+
*
|
|
22
|
+
* @returns the inspected token's `user_id` when the token is valid and bound to
|
|
23
|
+
* the configured app, otherwise `null`.
|
|
24
|
+
*/
|
|
25
|
+
async function verifyFacebookAccessToken(accessToken, options) {
|
|
26
|
+
const primaryClientId = getPrimaryClientId(options.clientId);
|
|
27
|
+
if (!primaryClientId || !options.clientSecret) return null;
|
|
28
|
+
const clientIds = Array.isArray(options.clientId) ? options.clientId : [options.clientId];
|
|
29
|
+
const { data, error } = await betterFetch("https://graph.facebook.com/debug_token", { query: {
|
|
30
|
+
input_token: accessToken,
|
|
31
|
+
access_token: `${primaryClientId}|${options.clientSecret}`
|
|
32
|
+
} });
|
|
33
|
+
if (error || !data?.data) return null;
|
|
34
|
+
const { is_valid, app_id, user_id } = data.data;
|
|
35
|
+
if (is_valid !== true || !app_id || !clientIds.includes(app_id) || !user_id) return null;
|
|
36
|
+
return user_id;
|
|
37
|
+
}
|
|
7
38
|
const facebook = (options) => {
|
|
8
39
|
return {
|
|
9
40
|
id: "facebook",
|
|
10
41
|
name: "Facebook",
|
|
11
|
-
async createAuthorizationURL({ state, scopes, redirectURI, loginHint }) {
|
|
42
|
+
async createAuthorizationURL({ state, scopes, redirectURI, loginHint, additionalParams }) {
|
|
43
|
+
if (!getPrimaryClientId(options.clientId) || !options.clientSecret) {
|
|
44
|
+
logger.error("Client ID and client secret are required for Facebook. Make sure to provide them in the options.");
|
|
45
|
+
throw new BetterAuthError("CLIENT_ID_AND_SECRET_REQUIRED");
|
|
46
|
+
}
|
|
12
47
|
const _scopes = options.disableDefaultScope ? [] : ["email", "public_profile"];
|
|
13
48
|
if (options.scope) _scopes.push(...options.scope);
|
|
14
49
|
if (scopes) _scopes.push(...scopes);
|
|
@@ -20,7 +55,10 @@ const facebook = (options) => {
|
|
|
20
55
|
state,
|
|
21
56
|
redirectURI,
|
|
22
57
|
loginHint,
|
|
23
|
-
additionalParams:
|
|
58
|
+
additionalParams: {
|
|
59
|
+
...options.configId ? { config_id: options.configId } : {},
|
|
60
|
+
...additionalParams ?? {}
|
|
61
|
+
}
|
|
24
62
|
});
|
|
25
63
|
},
|
|
26
64
|
validateAuthorizationCode: async ({ code, redirectURI }) => {
|
|
@@ -31,21 +69,12 @@ const facebook = (options) => {
|
|
|
31
69
|
tokenEndpoint: "https://graph.facebook.com/v24.0/oauth/access_token"
|
|
32
70
|
});
|
|
33
71
|
},
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
audience: options.clientId,
|
|
41
|
-
issuer: "https://www.facebook.com"
|
|
42
|
-
});
|
|
43
|
-
if (nonce && jwtClaims.nonce !== nonce) return false;
|
|
44
|
-
return !!jwtClaims;
|
|
45
|
-
} catch {
|
|
46
|
-
return false;
|
|
47
|
-
}
|
|
48
|
-
return true;
|
|
72
|
+
idToken: {
|
|
73
|
+
jwks: createRemoteJWKSet(new URL("https://limited.facebook.com/.well-known/oauth/openid/jwks/")),
|
|
74
|
+
issuer: "https://www.facebook.com",
|
|
75
|
+
audience: options.clientId,
|
|
76
|
+
algorithms: ["RS256"],
|
|
77
|
+
allowOpaqueToken: true
|
|
49
78
|
},
|
|
50
79
|
refreshAccessToken: options.refreshAccessToken ? options.refreshAccessToken : async (refreshToken) => {
|
|
51
80
|
return refreshAccessToken({
|
|
@@ -86,6 +115,10 @@ const facebook = (options) => {
|
|
|
86
115
|
data: profile
|
|
87
116
|
};
|
|
88
117
|
}
|
|
118
|
+
const accessToken = token.accessToken;
|
|
119
|
+
if (!accessToken) return null;
|
|
120
|
+
const tokenUserId = await verifyFacebookAccessToken(accessToken, options);
|
|
121
|
+
if (!tokenUserId) return null;
|
|
89
122
|
const { data: profile, error } = await betterFetch("https://graph.facebook.com/me?fields=" + [
|
|
90
123
|
"id",
|
|
91
124
|
"name",
|
|
@@ -94,9 +127,10 @@ const facebook = (options) => {
|
|
|
94
127
|
...options?.fields || []
|
|
95
128
|
].join(","), { auth: {
|
|
96
129
|
type: "Bearer",
|
|
97
|
-
token:
|
|
130
|
+
token: accessToken
|
|
98
131
|
} });
|
|
99
132
|
if (error) return null;
|
|
133
|
+
if (profile.id !== tokenUserId) return null;
|
|
100
134
|
const userMap = await options.mapProfileToUser?.(profile);
|
|
101
135
|
return {
|
|
102
136
|
user: {
|
|
@@ -104,7 +138,7 @@ const facebook = (options) => {
|
|
|
104
138
|
name: profile.name,
|
|
105
139
|
email: profile.email,
|
|
106
140
|
image: profile.picture.data.url,
|
|
107
|
-
emailVerified: profile.email_verified,
|
|
141
|
+
emailVerified: profile.email_verified ?? false,
|
|
108
142
|
...userMap
|
|
109
143
|
},
|
|
110
144
|
data: profile
|
|
@@ -16,7 +16,8 @@ declare const figma: (options: FigmaOptions) => {
|
|
|
16
16
|
state,
|
|
17
17
|
scopes,
|
|
18
18
|
codeVerifier,
|
|
19
|
-
redirectURI
|
|
19
|
+
redirectURI,
|
|
20
|
+
additionalParams
|
|
20
21
|
}: {
|
|
21
22
|
state: string;
|
|
22
23
|
codeVerifier: string;
|
|
@@ -24,6 +25,8 @@ declare const figma: (options: FigmaOptions) => {
|
|
|
24
25
|
redirectURI: string;
|
|
25
26
|
display?: string | undefined;
|
|
26
27
|
loginHint?: string | undefined;
|
|
28
|
+
idTokenNonce?: string | undefined;
|
|
29
|
+
additionalParams?: Record<string, string> | undefined;
|
|
27
30
|
}): Promise<URL>;
|
|
28
31
|
validateAuthorizationCode: ({
|
|
29
32
|
code,
|
|
@@ -37,6 +40,7 @@ declare const figma: (options: FigmaOptions) => {
|
|
|
37
40
|
}) => Promise<OAuth2Tokens>;
|
|
38
41
|
refreshAccessToken: (refreshToken: string) => Promise<OAuth2Tokens>;
|
|
39
42
|
getUserInfo(token: OAuth2Tokens & {
|
|
43
|
+
expectedIdTokenNonce?: string | undefined;
|
|
40
44
|
user?: {
|
|
41
45
|
name?: {
|
|
42
46
|
firstName?: string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { logger } from "../env/logger.mjs";
|
|
2
1
|
import { BetterAuthError } from "../error/index.mjs";
|
|
2
|
+
import { logger } from "../env/logger.mjs";
|
|
3
3
|
import { createAuthorizationURL } from "../oauth2/create-authorization-url.mjs";
|
|
4
4
|
import { refreshAccessToken } from "../oauth2/refresh-access-token.mjs";
|
|
5
5
|
import { validateAuthorizationCode } from "../oauth2/validate-authorization-code.mjs";
|
|
@@ -10,7 +10,7 @@ const figma = (options) => {
|
|
|
10
10
|
return {
|
|
11
11
|
id: "figma",
|
|
12
12
|
name: "Figma",
|
|
13
|
-
async createAuthorizationURL({ state, scopes, codeVerifier, redirectURI }) {
|
|
13
|
+
async createAuthorizationURL({ state, scopes, codeVerifier, redirectURI, additionalParams }) {
|
|
14
14
|
if (!options.clientId || !options.clientSecret) {
|
|
15
15
|
logger.error("Client Id and Client Secret are required for Figma. Make sure to provide them in the options.");
|
|
16
16
|
throw new BetterAuthError("CLIENT_ID_AND_SECRET_REQUIRED");
|
|
@@ -26,7 +26,8 @@ const figma = (options) => {
|
|
|
26
26
|
scopes: _scopes,
|
|
27
27
|
state,
|
|
28
28
|
codeVerifier,
|
|
29
|
-
redirectURI
|
|
29
|
+
redirectURI,
|
|
30
|
+
additionalParams
|
|
30
31
|
});
|
|
31
32
|
},
|
|
32
33
|
validateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {
|
|
@@ -23,7 +23,7 @@ interface GithubProfile {
|
|
|
23
23
|
company: string;
|
|
24
24
|
blog: string;
|
|
25
25
|
location: string;
|
|
26
|
-
email: string;
|
|
26
|
+
email: string | null;
|
|
27
27
|
hireable: boolean;
|
|
28
28
|
bio: string;
|
|
29
29
|
twitter_username: string;
|
|
@@ -57,7 +57,8 @@ declare const github: (options: GithubOptions) => {
|
|
|
57
57
|
scopes,
|
|
58
58
|
loginHint,
|
|
59
59
|
codeVerifier,
|
|
60
|
-
redirectURI
|
|
60
|
+
redirectURI,
|
|
61
|
+
additionalParams
|
|
61
62
|
}: {
|
|
62
63
|
state: string;
|
|
63
64
|
codeVerifier: string;
|
|
@@ -65,6 +66,8 @@ declare const github: (options: GithubOptions) => {
|
|
|
65
66
|
redirectURI: string;
|
|
66
67
|
display?: string | undefined;
|
|
67
68
|
loginHint?: string | undefined;
|
|
69
|
+
idTokenNonce?: string | undefined;
|
|
70
|
+
additionalParams?: Record<string, string> | undefined;
|
|
68
71
|
}): Promise<URL>;
|
|
69
72
|
validateAuthorizationCode: ({
|
|
70
73
|
code,
|
|
@@ -78,6 +81,7 @@ declare const github: (options: GithubOptions) => {
|
|
|
78
81
|
}) => Promise<OAuth2Tokens | null>;
|
|
79
82
|
refreshAccessToken: (refreshToken: string) => Promise<OAuth2Tokens>;
|
|
80
83
|
getUserInfo(token: OAuth2Tokens & {
|
|
84
|
+
expectedIdTokenNonce?: string | undefined;
|
|
81
85
|
user?: {
|
|
82
86
|
name?: {
|
|
83
87
|
firstName?: string;
|