@better-auth/core 1.5.0-beta.2 → 1.5.0-beta.20
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/LICENSE.md +15 -12
- package/README.md +17 -0
- package/dist/api/index.d.mts +280 -2
- package/dist/api/index.mjs +4 -2
- package/dist/api/index.mjs.map +1 -0
- package/dist/async_hooks/index.d.mts +2 -1
- package/dist/async_hooks/index.mjs +2 -1
- package/dist/async_hooks/index.mjs.map +1 -0
- package/dist/async_hooks/pure.index.d.mts +2 -1
- package/dist/async_hooks/pure.index.mjs +2 -1
- package/dist/async_hooks/pure.index.mjs.map +1 -0
- package/dist/context/endpoint-context.d.mts +20 -0
- package/dist/context/endpoint-context.mjs +32 -0
- package/dist/context/endpoint-context.mjs.map +1 -0
- package/dist/context/global.d.mts +7 -0
- package/dist/context/global.mjs +38 -0
- package/dist/context/global.mjs.map +1 -0
- package/dist/context/index.d.mts +5 -53
- package/dist/context/index.mjs +5 -2
- package/dist/context/request-state.d.mts +28 -0
- package/dist/context/request-state.mjs +50 -0
- package/dist/context/request-state.mjs.map +1 -0
- package/dist/context/transaction.d.mts +25 -0
- package/dist/context/transaction.mjs +96 -0
- package/dist/context/transaction.mjs.map +1 -0
- package/dist/db/adapter/factory.d.mts +20 -0
- package/dist/db/adapter/factory.mjs +725 -0
- package/dist/db/adapter/factory.mjs.map +1 -0
- package/dist/db/adapter/get-default-field-name.d.mts +19 -0
- package/dist/db/adapter/get-default-field-name.mjs +39 -0
- package/dist/db/adapter/get-default-field-name.mjs.map +1 -0
- package/dist/db/adapter/get-default-model-name.d.mts +13 -0
- package/dist/db/adapter/get-default-model-name.mjs +33 -0
- package/dist/db/adapter/get-default-model-name.mjs.map +1 -0
- package/dist/db/adapter/get-field-attributes.d.mts +30 -0
- package/dist/db/adapter/get-field-attributes.mjs +40 -0
- package/dist/db/adapter/get-field-attributes.mjs.map +1 -0
- package/dist/db/adapter/get-field-name.d.mts +19 -0
- package/dist/db/adapter/get-field-name.mjs +34 -0
- package/dist/db/adapter/get-field-name.mjs.map +1 -0
- package/dist/db/adapter/get-id-field.d.mts +40 -0
- package/dist/db/adapter/get-id-field.mjs +68 -0
- package/dist/db/adapter/get-id-field.mjs.map +1 -0
- package/dist/db/adapter/get-model-name.d.mts +13 -0
- package/dist/db/adapter/get-model-name.mjs +24 -0
- package/dist/db/adapter/get-model-name.mjs.map +1 -0
- package/dist/db/adapter/index.d.mts +520 -2
- package/dist/db/adapter/index.mjs +27 -972
- package/dist/db/adapter/index.mjs.map +1 -0
- package/dist/db/adapter/types.d.mts +108 -0
- package/dist/db/adapter/utils.d.mts +8 -0
- package/dist/db/adapter/utils.mjs +39 -0
- package/dist/db/adapter/utils.mjs.map +1 -0
- package/dist/db/get-tables.d.mts +9 -0
- package/dist/{get-tables-CMc_Emww.mjs → db/get-tables.mjs} +52 -39
- package/dist/db/get-tables.mjs.map +1 -0
- package/dist/db/index.d.mts +10 -2
- package/dist/db/index.mjs +7 -60
- package/dist/db/plugin.d.mts +13 -0
- package/dist/db/schema/account.d.mts +30 -0
- package/dist/db/schema/account.mjs +20 -0
- package/dist/db/schema/account.mjs.map +1 -0
- package/dist/db/schema/rate-limit.d.mts +20 -0
- package/dist/db/schema/rate-limit.mjs +12 -0
- package/dist/db/schema/rate-limit.mjs.map +1 -0
- package/dist/db/schema/session.d.mts +25 -0
- package/dist/db/schema/session.mjs +15 -0
- package/dist/db/schema/session.mjs.map +1 -0
- package/dist/db/schema/shared.d.mts +11 -0
- package/dist/db/schema/shared.mjs +12 -0
- package/dist/db/schema/shared.mjs.map +1 -0
- package/dist/db/schema/user.d.mts +24 -0
- package/dist/db/schema/user.mjs +14 -0
- package/dist/db/schema/user.mjs.map +1 -0
- package/dist/db/schema/verification.d.mts +23 -0
- package/dist/db/schema/verification.mjs +13 -0
- package/dist/db/schema/verification.mjs.map +1 -0
- package/dist/db/type.d.mts +169 -0
- package/dist/env/color-depth.d.mts +5 -0
- package/dist/env/color-depth.mjs +89 -0
- package/dist/env/color-depth.mjs.map +1 -0
- package/dist/env/env-impl.d.mts +33 -0
- package/dist/env/env-impl.mjs +83 -0
- package/dist/env/env-impl.mjs.map +1 -0
- package/dist/env/index.d.mts +4 -2
- package/dist/env/index.mjs +3 -1
- package/dist/{index-BRBu0-5h.d.mts → env/logger.d.mts} +2 -35
- package/dist/env/logger.mjs +82 -0
- package/dist/env/logger.mjs.map +1 -0
- package/dist/error/codes.d.mts +69 -0
- package/dist/{error-C7mY-p0f.mjs → error/codes.mjs} +7 -30
- package/dist/error/codes.mjs.map +1 -0
- package/dist/error/index.d.mts +6 -187
- package/dist/error/index.mjs +29 -4
- package/dist/error/index.mjs.map +1 -0
- package/dist/index.d.mts +8 -2
- package/dist/oauth2/client-credentials-token.d.mts +58 -0
- package/dist/oauth2/client-credentials-token.mjs +67 -0
- package/dist/oauth2/client-credentials-token.mjs.map +1 -0
- package/dist/oauth2/create-authorization-url.d.mts +48 -0
- package/dist/oauth2/create-authorization-url.mjs +44 -0
- package/dist/oauth2/create-authorization-url.mjs.map +1 -0
- package/dist/oauth2/index.d.mts +8 -2
- package/dist/oauth2/index.mjs +7 -3
- package/dist/oauth2/oauth-provider.d.mts +195 -0
- package/dist/oauth2/refresh-access-token.d.mts +56 -0
- package/dist/oauth2/refresh-access-token.mjs +76 -0
- package/dist/oauth2/refresh-access-token.mjs.map +1 -0
- package/dist/oauth2/utils.d.mts +8 -0
- package/dist/oauth2/utils.mjs +28 -0
- package/dist/oauth2/utils.mjs.map +1 -0
- package/dist/oauth2/validate-authorization-code.d.mts +88 -0
- package/dist/oauth2/validate-authorization-code.mjs +83 -0
- package/dist/oauth2/validate-authorization-code.mjs.map +1 -0
- package/dist/oauth2/verify.d.mts +43 -0
- package/dist/oauth2/verify.mjs +96 -0
- package/dist/oauth2/verify.mjs.map +1 -0
- package/dist/social-providers/apple.d.mts +120 -0
- package/dist/social-providers/apple.mjs +105 -0
- package/dist/social-providers/apple.mjs.map +1 -0
- package/dist/social-providers/atlassian.d.mts +73 -0
- package/dist/social-providers/atlassian.mjs +84 -0
- package/dist/social-providers/atlassian.mjs.map +1 -0
- package/dist/social-providers/cognito.d.mts +88 -0
- package/dist/social-providers/cognito.mjs +166 -0
- package/dist/social-providers/cognito.mjs.map +1 -0
- package/dist/social-providers/discord.d.mts +127 -0
- package/dist/social-providers/discord.mjs +65 -0
- package/dist/social-providers/discord.mjs.map +1 -0
- package/dist/social-providers/dropbox.d.mts +72 -0
- package/dist/social-providers/dropbox.mjs +76 -0
- package/dist/social-providers/dropbox.mjs.map +1 -0
- package/dist/social-providers/facebook.d.mts +82 -0
- package/dist/social-providers/facebook.mjs +121 -0
- package/dist/social-providers/facebook.mjs.map +1 -0
- package/dist/social-providers/figma.d.mts +64 -0
- package/dist/social-providers/figma.mjs +87 -0
- package/dist/social-providers/figma.mjs.map +1 -0
- package/dist/social-providers/github.d.mts +105 -0
- package/dist/social-providers/github.mjs +97 -0
- package/dist/social-providers/github.mjs.map +1 -0
- package/dist/social-providers/gitlab.d.mts +126 -0
- package/dist/social-providers/gitlab.mjs +83 -0
- package/dist/social-providers/gitlab.mjs.map +1 -0
- package/dist/social-providers/google.d.mts +100 -0
- package/dist/social-providers/google.mjs +113 -0
- package/dist/social-providers/google.mjs.map +1 -0
- package/dist/social-providers/huggingface.d.mts +86 -0
- package/dist/social-providers/huggingface.mjs +76 -0
- package/dist/social-providers/huggingface.mjs.map +1 -0
- package/dist/social-providers/index.d.mts +1777 -2
- package/dist/social-providers/index.mjs +37 -2570
- package/dist/social-providers/index.mjs.map +1 -0
- package/dist/social-providers/kakao.d.mts +164 -0
- package/dist/social-providers/kakao.mjs +73 -0
- package/dist/social-providers/kakao.mjs.map +1 -0
- package/dist/social-providers/kick.d.mts +76 -0
- package/dist/social-providers/kick.mjs +72 -0
- package/dist/social-providers/kick.mjs.map +1 -0
- package/dist/social-providers/line.d.mts +108 -0
- package/dist/social-providers/line.mjs +114 -0
- package/dist/social-providers/line.mjs.map +1 -0
- package/dist/social-providers/linear.d.mts +71 -0
- package/dist/social-providers/linear.mjs +89 -0
- package/dist/social-providers/linear.mjs.map +1 -0
- package/dist/social-providers/linkedin.d.mts +70 -0
- package/dist/social-providers/linkedin.mjs +77 -0
- package/dist/social-providers/linkedin.mjs.map +1 -0
- package/dist/social-providers/microsoft-entra-id.d.mts +177 -0
- package/dist/social-providers/microsoft-entra-id.mjs +140 -0
- package/dist/social-providers/microsoft-entra-id.mjs.map +1 -0
- package/dist/social-providers/naver.d.mts +95 -0
- package/dist/social-providers/naver.mjs +68 -0
- package/dist/social-providers/naver.mjs.map +1 -0
- package/dist/social-providers/notion.d.mts +67 -0
- package/dist/social-providers/notion.mjs +76 -0
- package/dist/social-providers/notion.mjs.map +1 -0
- package/dist/social-providers/paybin.d.mts +74 -0
- package/dist/social-providers/paybin.mjs +86 -0
- package/dist/social-providers/paybin.mjs.map +1 -0
- package/dist/social-providers/paypal.d.mts +132 -0
- package/dist/social-providers/paypal.mjs +145 -0
- package/dist/social-providers/paypal.mjs.map +1 -0
- package/dist/social-providers/polar.d.mts +77 -0
- package/dist/social-providers/polar.mjs +74 -0
- package/dist/social-providers/polar.mjs.map +1 -0
- package/dist/social-providers/railway.d.mts +68 -0
- package/dist/social-providers/railway.mjs +78 -0
- package/dist/social-providers/railway.mjs.map +1 -0
- package/dist/social-providers/reddit.d.mts +65 -0
- package/dist/social-providers/reddit.mjs +84 -0
- package/dist/social-providers/reddit.mjs.map +1 -0
- package/dist/social-providers/roblox.d.mts +73 -0
- package/dist/social-providers/roblox.mjs +60 -0
- package/dist/social-providers/roblox.mjs.map +1 -0
- package/dist/social-providers/salesforce.d.mts +82 -0
- package/dist/social-providers/salesforce.mjs +92 -0
- package/dist/social-providers/salesforce.mjs.map +1 -0
- package/dist/social-providers/slack.d.mts +86 -0
- package/dist/social-providers/slack.mjs +69 -0
- package/dist/social-providers/slack.mjs.map +1 -0
- package/dist/social-providers/spotify.d.mts +66 -0
- package/dist/social-providers/spotify.mjs +72 -0
- package/dist/social-providers/spotify.mjs.map +1 -0
- package/dist/social-providers/tiktok.d.mts +171 -0
- package/dist/social-providers/tiktok.mjs +63 -0
- package/dist/social-providers/tiktok.mjs.map +1 -0
- package/dist/social-providers/twitch.d.mts +82 -0
- package/dist/social-providers/twitch.mjs +79 -0
- package/dist/social-providers/twitch.mjs.map +1 -0
- package/dist/social-providers/twitter.d.mts +129 -0
- package/dist/social-providers/twitter.mjs +88 -0
- package/dist/social-providers/twitter.mjs.map +1 -0
- package/dist/social-providers/vercel.d.mts +65 -0
- package/dist/social-providers/vercel.mjs +62 -0
- package/dist/social-providers/vercel.mjs.map +1 -0
- package/dist/social-providers/vk.d.mts +73 -0
- package/dist/social-providers/vk.mjs +84 -0
- package/dist/social-providers/vk.mjs.map +1 -0
- package/dist/social-providers/zoom.d.mts +166 -0
- package/dist/social-providers/zoom.mjs +73 -0
- package/dist/social-providers/zoom.mjs.map +1 -0
- package/dist/types/context.d.mts +274 -0
- package/dist/types/cookie.d.mts +16 -0
- package/dist/types/helper.d.mts +11 -0
- package/dist/types/index.d.mts +8 -0
- package/dist/types/init-options.d.mts +1298 -0
- package/dist/types/plugin-client.d.mts +113 -0
- package/dist/types/plugin.d.mts +125 -0
- package/dist/utils/db.d.mts +12 -0
- package/dist/utils/db.mjs +17 -0
- package/dist/utils/db.mjs.map +1 -0
- package/dist/utils/deprecate.d.mts +10 -0
- package/dist/utils/deprecate.mjs +18 -0
- package/dist/utils/deprecate.mjs.map +1 -0
- package/dist/utils/{index.d.mts → error-codes.d.mts} +9 -16
- package/dist/utils/error-codes.mjs +12 -0
- package/dist/utils/error-codes.mjs.map +1 -0
- package/dist/utils/id.d.mts +5 -0
- package/dist/utils/id.mjs +10 -0
- package/dist/utils/id.mjs.map +1 -0
- package/dist/utils/ip.d.mts +55 -0
- package/dist/utils/ip.mjs +119 -0
- package/dist/utils/ip.mjs.map +1 -0
- package/dist/utils/json.d.mts +5 -0
- package/dist/utils/json.mjs +26 -0
- package/dist/utils/json.mjs.map +1 -0
- package/dist/utils/string.d.mts +5 -0
- package/dist/utils/string.mjs +8 -0
- package/dist/utils/string.mjs.map +1 -0
- package/dist/utils/url.d.mts +21 -0
- package/dist/utils/url.mjs +33 -0
- package/dist/utils/url.mjs.map +1 -0
- package/package.json +36 -18
- package/src/context/endpoint-context.ts +7 -6
- package/src/context/global.ts +57 -0
- package/src/context/index.ts +2 -0
- package/src/context/request-state.ts +7 -6
- package/src/context/transaction.ts +77 -14
- package/src/db/adapter/factory.ts +54 -86
- package/src/db/adapter/get-default-model-name.ts +1 -1
- package/src/db/adapter/get-id-field.ts +4 -6
- package/src/db/adapter/index.ts +20 -15
- package/src/db/adapter/types.ts +2 -41
- package/src/db/get-tables.ts +54 -37
- package/src/db/index.ts +30 -5
- package/src/db/schema/account.ts +16 -3
- package/src/db/schema/rate-limit.ts +16 -1
- package/src/db/schema/session.ts +15 -3
- package/src/db/schema/user.ts +15 -3
- package/src/db/schema/verification.ts +16 -3
- package/src/db/test/get-tables.test.ts +33 -0
- package/src/db/type.ts +154 -1
- package/src/env/env-impl.ts +2 -2
- package/src/env/logger.ts +1 -1
- package/src/error/codes.ts +18 -1
- package/src/error/index.ts +2 -3
- package/src/oauth2/client-credentials-token.ts +26 -2
- package/src/oauth2/create-authorization-url.ts +4 -2
- package/src/oauth2/index.ts +3 -0
- package/src/oauth2/oauth-provider.ts +7 -1
- package/src/oauth2/refresh-access-token.test.ts +90 -0
- package/src/oauth2/refresh-access-token.ts +37 -4
- package/src/oauth2/validate-authorization-code.ts +55 -29
- package/src/oauth2/validate-token.test.ts +229 -0
- package/src/social-providers/apple.ts +38 -29
- package/src/social-providers/cognito.ts +6 -5
- package/src/social-providers/dropbox.ts +1 -1
- package/src/social-providers/facebook.ts +3 -3
- package/src/social-providers/figma.ts +5 -3
- package/src/social-providers/github.ts +26 -4
- package/src/social-providers/gitlab.ts +2 -2
- package/src/social-providers/google.ts +18 -14
- package/src/social-providers/huggingface.ts +1 -1
- package/src/social-providers/index.ts +9 -5
- package/src/social-providers/kakao.ts +1 -1
- package/src/social-providers/line.ts +1 -1
- package/src/social-providers/microsoft-entra-id.ts +84 -1
- package/src/social-providers/naver.ts +1 -1
- package/src/social-providers/notion.ts +1 -1
- package/src/social-providers/paybin.ts +1 -5
- package/src/social-providers/polar.ts +1 -1
- package/src/social-providers/railway.ts +100 -0
- package/src/social-providers/tiktok.ts +2 -1
- package/src/social-providers/vercel.ts +1 -1
- package/src/social-providers/zoom.ts +0 -8
- package/src/types/context.ts +241 -132
- package/src/types/cookie.ts +6 -4
- package/src/types/helper.ts +9 -0
- package/src/types/index.ts +19 -2
- package/src/types/init-options.ts +301 -186
- package/src/types/plugin-client.ts +1 -0
- package/src/types/plugin.ts +11 -6
- package/src/utils/db.ts +20 -0
- package/src/utils/deprecate.test.ts +71 -0
- package/src/utils/deprecate.ts +21 -0
- package/src/utils/error-codes.ts +12 -9
- package/src/utils/ip.test.ts +255 -0
- package/src/utils/ip.ts +211 -0
- package/src/utils/url.ts +43 -0
- package/.turbo/turbo-build.log +0 -43
- package/dist/context-DblZrIwO.mjs +0 -114
- package/dist/env-DbssmzoK.mjs +0 -245
- package/dist/index-BpRqx5_q.d.mts +0 -7833
- package/dist/oauth2-BjWM15hm.mjs +0 -326
- package/dist/utils/index.mjs +0 -4
- package/dist/utils-s65Fz0OM.mjs +0 -47
- package/src/utils/index.ts +0 -4
- package/tsconfig.json +0 -7
- package/tsdown.config.ts +0 -22
- package/vitest.config.ts +0 -3
|
@@ -1,7 +1,34 @@
|
|
|
1
1
|
import { base64 } from "@better-auth/utils/base64";
|
|
2
2
|
import { betterFetch } from "@better-fetch/fetch";
|
|
3
|
+
import type { AwaitableFunction } from "../types";
|
|
3
4
|
import type { OAuth2Tokens, ProviderOptions } from "./oauth-provider";
|
|
4
5
|
|
|
6
|
+
export async function refreshAccessTokenRequest({
|
|
7
|
+
refreshToken,
|
|
8
|
+
options,
|
|
9
|
+
authentication,
|
|
10
|
+
extraParams,
|
|
11
|
+
resource,
|
|
12
|
+
}: {
|
|
13
|
+
refreshToken: string;
|
|
14
|
+
options: AwaitableFunction<Partial<ProviderOptions>>;
|
|
15
|
+
authentication?: ("basic" | "post") | undefined;
|
|
16
|
+
extraParams?: Record<string, string> | undefined;
|
|
17
|
+
resource?: (string | string[]) | undefined;
|
|
18
|
+
}) {
|
|
19
|
+
options = typeof options === "function" ? await options() : options;
|
|
20
|
+
return createRefreshAccessTokenRequest({
|
|
21
|
+
refreshToken,
|
|
22
|
+
options,
|
|
23
|
+
authentication,
|
|
24
|
+
extraParams,
|
|
25
|
+
resource,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @deprecated use async'd refreshAccessTokenRequest instead
|
|
31
|
+
*/
|
|
5
32
|
export function createRefreshAccessTokenRequest({
|
|
6
33
|
refreshToken,
|
|
7
34
|
options,
|
|
@@ -10,7 +37,7 @@ export function createRefreshAccessTokenRequest({
|
|
|
10
37
|
resource,
|
|
11
38
|
}: {
|
|
12
39
|
refreshToken: string;
|
|
13
|
-
options:
|
|
40
|
+
options: ProviderOptions;
|
|
14
41
|
authentication?: ("basic" | "post") | undefined;
|
|
15
42
|
extraParams?: Record<string, string> | undefined;
|
|
16
43
|
resource?: (string | string[]) | undefined;
|
|
@@ -80,10 +107,8 @@ export async function refreshAccessToken({
|
|
|
80
107
|
tokenEndpoint: string;
|
|
81
108
|
authentication?: ("basic" | "post") | undefined;
|
|
82
109
|
extraParams?: Record<string, string> | undefined;
|
|
83
|
-
/** @deprecated always "refresh_token" */
|
|
84
|
-
grantType?: string | undefined;
|
|
85
110
|
}): Promise<OAuth2Tokens> {
|
|
86
|
-
const { body, headers } = createRefreshAccessTokenRequest({
|
|
111
|
+
const { body, headers } = await createRefreshAccessTokenRequest({
|
|
87
112
|
refreshToken,
|
|
88
113
|
options,
|
|
89
114
|
authentication,
|
|
@@ -94,6 +119,7 @@ export async function refreshAccessToken({
|
|
|
94
119
|
access_token: string;
|
|
95
120
|
refresh_token?: string | undefined;
|
|
96
121
|
expires_in?: number | undefined;
|
|
122
|
+
refresh_token_expires_in?: number | undefined;
|
|
97
123
|
token_type?: string | undefined;
|
|
98
124
|
scope?: string | undefined;
|
|
99
125
|
id_token?: string | undefined;
|
|
@@ -120,5 +146,12 @@ export async function refreshAccessToken({
|
|
|
120
146
|
);
|
|
121
147
|
}
|
|
122
148
|
|
|
149
|
+
if (data.refresh_token_expires_in) {
|
|
150
|
+
const now = new Date();
|
|
151
|
+
tokens.refreshTokenExpiresAt = new Date(
|
|
152
|
+
now.getTime() + data.refresh_token_expires_in * 1000,
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
|
|
123
156
|
return tokens;
|
|
124
157
|
}
|
|
@@ -1,9 +1,48 @@
|
|
|
1
1
|
import { base64 } from "@better-auth/utils/base64";
|
|
2
2
|
import { betterFetch } from "@better-fetch/fetch";
|
|
3
|
-
import { jwtVerify } from "jose";
|
|
3
|
+
import { createRemoteJWKSet, jwtVerify } from "jose";
|
|
4
|
+
import type { AwaitableFunction } from "../types";
|
|
4
5
|
import type { ProviderOptions } from "./index";
|
|
5
6
|
import { getOAuth2Tokens } from "./index";
|
|
6
7
|
|
|
8
|
+
export async function authorizationCodeRequest({
|
|
9
|
+
code,
|
|
10
|
+
codeVerifier,
|
|
11
|
+
redirectURI,
|
|
12
|
+
options,
|
|
13
|
+
authentication,
|
|
14
|
+
deviceId,
|
|
15
|
+
headers,
|
|
16
|
+
additionalParams = {},
|
|
17
|
+
resource,
|
|
18
|
+
}: {
|
|
19
|
+
code: string;
|
|
20
|
+
redirectURI: string;
|
|
21
|
+
options: AwaitableFunction<Partial<ProviderOptions>>;
|
|
22
|
+
codeVerifier?: string | undefined;
|
|
23
|
+
deviceId?: string | undefined;
|
|
24
|
+
authentication?: ("basic" | "post") | undefined;
|
|
25
|
+
headers?: Record<string, string> | undefined;
|
|
26
|
+
additionalParams?: Record<string, string> | undefined;
|
|
27
|
+
resource?: (string | string[]) | undefined;
|
|
28
|
+
}) {
|
|
29
|
+
options = typeof options === "function" ? await options() : options;
|
|
30
|
+
return createAuthorizationCodeRequest({
|
|
31
|
+
code,
|
|
32
|
+
codeVerifier,
|
|
33
|
+
redirectURI,
|
|
34
|
+
options,
|
|
35
|
+
authentication,
|
|
36
|
+
deviceId,
|
|
37
|
+
headers,
|
|
38
|
+
additionalParams,
|
|
39
|
+
resource,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @deprecated use async'd authorizationCodeRequest instead
|
|
45
|
+
*/
|
|
7
46
|
export function createAuthorizationCodeRequest({
|
|
8
47
|
code,
|
|
9
48
|
codeVerifier,
|
|
@@ -31,6 +70,7 @@ export function createAuthorizationCodeRequest({
|
|
|
31
70
|
accept: "application/json",
|
|
32
71
|
...headers,
|
|
33
72
|
};
|
|
73
|
+
|
|
34
74
|
body.set("grant_type", "authorization_code");
|
|
35
75
|
body.set("code", code);
|
|
36
76
|
codeVerifier && body.set("code_verifier", codeVerifier);
|
|
@@ -90,7 +130,7 @@ export async function validateAuthorizationCode({
|
|
|
90
130
|
}: {
|
|
91
131
|
code: string;
|
|
92
132
|
redirectURI: string;
|
|
93
|
-
options: Partial<ProviderOptions
|
|
133
|
+
options: AwaitableFunction<Partial<ProviderOptions>>;
|
|
94
134
|
codeVerifier?: string | undefined;
|
|
95
135
|
deviceId?: string | undefined;
|
|
96
136
|
tokenEndpoint: string;
|
|
@@ -99,7 +139,7 @@ export async function validateAuthorizationCode({
|
|
|
99
139
|
additionalParams?: Record<string, string> | undefined;
|
|
100
140
|
resource?: (string | string[]) | undefined;
|
|
101
141
|
}) {
|
|
102
|
-
const { body, headers: requestHeaders } =
|
|
142
|
+
const { body, headers: requestHeaders } = await authorizationCodeRequest({
|
|
103
143
|
code,
|
|
104
144
|
codeVerifier,
|
|
105
145
|
redirectURI,
|
|
@@ -116,7 +156,6 @@ export async function validateAuthorizationCode({
|
|
|
116
156
|
body: body,
|
|
117
157
|
headers: requestHeaders,
|
|
118
158
|
});
|
|
119
|
-
|
|
120
159
|
if (error) {
|
|
121
160
|
throw error;
|
|
122
161
|
}
|
|
@@ -124,31 +163,18 @@ export async function validateAuthorizationCode({
|
|
|
124
163
|
return tokens;
|
|
125
164
|
}
|
|
126
165
|
|
|
127
|
-
export async function validateToken(
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
headers: {
|
|
140
|
-
accept: "application/json",
|
|
141
|
-
},
|
|
166
|
+
export async function validateToken(
|
|
167
|
+
token: string,
|
|
168
|
+
jwksEndpoint: string,
|
|
169
|
+
options?: {
|
|
170
|
+
audience?: string | string[];
|
|
171
|
+
issuer?: string | string[];
|
|
172
|
+
},
|
|
173
|
+
) {
|
|
174
|
+
const jwks = createRemoteJWKSet(new URL(jwksEndpoint));
|
|
175
|
+
const verified = await jwtVerify(token, jwks, {
|
|
176
|
+
audience: options?.audience,
|
|
177
|
+
issuer: options?.issuer,
|
|
142
178
|
});
|
|
143
|
-
if (error) {
|
|
144
|
-
throw error;
|
|
145
|
-
}
|
|
146
|
-
const keys = data["keys"];
|
|
147
|
-
const header = JSON.parse(atob(token.split(".")[0]!));
|
|
148
|
-
const key = keys.find((key) => key.kid === header.kid);
|
|
149
|
-
if (!key) {
|
|
150
|
-
throw new Error("Key not found");
|
|
151
|
-
}
|
|
152
|
-
const verified = await jwtVerify(token, key);
|
|
153
179
|
return verified;
|
|
154
180
|
}
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import type { JWK } from "jose";
|
|
2
|
+
import { exportJWK, generateKeyPair, SignJWT } from "jose";
|
|
3
|
+
import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
|
|
4
|
+
import { validateToken } from "./validate-authorization-code";
|
|
5
|
+
|
|
6
|
+
describe("validateToken", () => {
|
|
7
|
+
const originalFetch = globalThis.fetch;
|
|
8
|
+
const mockedFetch = vi.fn() as unknown as typeof fetch &
|
|
9
|
+
ReturnType<typeof vi.fn>;
|
|
10
|
+
|
|
11
|
+
beforeAll(() => {
|
|
12
|
+
globalThis.fetch = mockedFetch;
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
afterAll(() => {
|
|
16
|
+
globalThis.fetch = originalFetch;
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
async function createTestJWKS(alg: string, crv?: string) {
|
|
20
|
+
const { publicKey, privateKey } = await generateKeyPair(alg, {
|
|
21
|
+
crv,
|
|
22
|
+
extractable: true,
|
|
23
|
+
});
|
|
24
|
+
const publicJWK = await exportJWK(publicKey);
|
|
25
|
+
const privateJWK = await exportJWK(privateKey);
|
|
26
|
+
const kid = `test-key-${Date.now()}`;
|
|
27
|
+
publicJWK.kid = kid;
|
|
28
|
+
publicJWK.alg = alg;
|
|
29
|
+
privateJWK.kid = kid;
|
|
30
|
+
privateJWK.alg = alg;
|
|
31
|
+
return { publicJWK, privateJWK, kid, publicKey, privateKey };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function createSignedToken(
|
|
35
|
+
privateKey: CryptoKey,
|
|
36
|
+
alg: string,
|
|
37
|
+
kid: string,
|
|
38
|
+
payload: Record<string, unknown> = {},
|
|
39
|
+
) {
|
|
40
|
+
return await new SignJWT({
|
|
41
|
+
sub: "user-123",
|
|
42
|
+
email: "test@example.com",
|
|
43
|
+
iss: "https://example.com",
|
|
44
|
+
aud: "test-client",
|
|
45
|
+
...payload,
|
|
46
|
+
})
|
|
47
|
+
.setProtectedHeader({ alg, kid })
|
|
48
|
+
.setIssuedAt()
|
|
49
|
+
.setExpirationTime("1h")
|
|
50
|
+
.sign(privateKey);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function mockJWKSResponse(...publicJWKs: JWK[]) {
|
|
54
|
+
mockedFetch.mockResolvedValueOnce(
|
|
55
|
+
new Response(JSON.stringify({ keys: publicJWKs }), {
|
|
56
|
+
status: 200,
|
|
57
|
+
headers: { "content-type": "application/json" },
|
|
58
|
+
}),
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
it("should verify RS256 signed token", async () => {
|
|
63
|
+
const { publicJWK, privateKey, kid } = await createTestJWKS("RS256");
|
|
64
|
+
const token = await createSignedToken(privateKey, "RS256", kid);
|
|
65
|
+
mockJWKSResponse(publicJWK);
|
|
66
|
+
|
|
67
|
+
const result = await validateToken(
|
|
68
|
+
token,
|
|
69
|
+
"https://example.com/.well-known/jwks",
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
expect(result).toBeDefined();
|
|
73
|
+
expect(result.payload.sub).toBe("user-123");
|
|
74
|
+
expect(result.payload.email).toBe("test@example.com");
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("should verify ES256 signed token", async () => {
|
|
78
|
+
const { publicJWK, privateKey, kid } = await createTestJWKS("ES256");
|
|
79
|
+
const token = await createSignedToken(privateKey, "ES256", kid);
|
|
80
|
+
mockJWKSResponse(publicJWK);
|
|
81
|
+
|
|
82
|
+
const result = await validateToken(
|
|
83
|
+
token,
|
|
84
|
+
"https://example.com/.well-known/jwks",
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
expect(result).toBeDefined();
|
|
88
|
+
expect(result.payload.sub).toBe("user-123");
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("should verify EdDSA (Ed25519) signed token", async () => {
|
|
92
|
+
const { publicJWK, privateKey, kid } = await createTestJWKS(
|
|
93
|
+
"EdDSA",
|
|
94
|
+
"Ed25519",
|
|
95
|
+
);
|
|
96
|
+
const token = await createSignedToken(privateKey, "EdDSA", kid);
|
|
97
|
+
mockJWKSResponse(publicJWK);
|
|
98
|
+
|
|
99
|
+
const result = await validateToken(
|
|
100
|
+
token,
|
|
101
|
+
"https://example.com/.well-known/jwks",
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
expect(result).toBeDefined();
|
|
105
|
+
expect(result.payload.sub).toBe("user-123");
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it("should throw when kid doesn't match any key", async () => {
|
|
109
|
+
const { publicJWK, privateKey } = await createTestJWKS("RS256");
|
|
110
|
+
publicJWK.kid = "different-kid";
|
|
111
|
+
const token = await createSignedToken(privateKey, "RS256", "original-kid");
|
|
112
|
+
mockJWKSResponse(publicJWK);
|
|
113
|
+
|
|
114
|
+
await expect(
|
|
115
|
+
validateToken(token, "https://example.com/.well-known/jwks"),
|
|
116
|
+
).rejects.toThrow();
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it("should find correct key when multiple keys exist", async () => {
|
|
120
|
+
const key1 = await createTestJWKS("RS256");
|
|
121
|
+
const key2 = await createTestJWKS("RS256");
|
|
122
|
+
const key3 = await createTestJWKS("ES256");
|
|
123
|
+
const token = await createSignedToken(key2.privateKey, "RS256", key2.kid);
|
|
124
|
+
mockJWKSResponse(key1.publicJWK, key2.publicJWK, key3.publicJWK);
|
|
125
|
+
|
|
126
|
+
const result = await validateToken(
|
|
127
|
+
token,
|
|
128
|
+
"https://example.com/.well-known/jwks",
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
expect(result).toBeDefined();
|
|
132
|
+
expect(result.payload.sub).toBe("user-123");
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it("should throw when JWKS returns empty keys array", async () => {
|
|
136
|
+
const { privateKey, kid } = await createTestJWKS("RS256");
|
|
137
|
+
const token = await createSignedToken(privateKey, "RS256", kid);
|
|
138
|
+
mockJWKSResponse();
|
|
139
|
+
|
|
140
|
+
await expect(
|
|
141
|
+
validateToken(token, "https://example.com/.well-known/jwks"),
|
|
142
|
+
).rejects.toThrow();
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it("should throw when JWKS fetch fails", async () => {
|
|
146
|
+
const { privateKey, kid } = await createTestJWKS("RS256");
|
|
147
|
+
const token = await createSignedToken(privateKey, "RS256", kid);
|
|
148
|
+
mockedFetch.mockResolvedValueOnce(
|
|
149
|
+
new Response("Internal Server Error", { status: 500 }),
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
await expect(
|
|
153
|
+
validateToken(token, "https://example.com/.well-known/jwks"),
|
|
154
|
+
).rejects.toBeDefined();
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it("should verify token with matching audience", async () => {
|
|
158
|
+
const { publicJWK, privateKey, kid } = await createTestJWKS("RS256");
|
|
159
|
+
const token = await createSignedToken(privateKey, "RS256", kid);
|
|
160
|
+
mockJWKSResponse(publicJWK);
|
|
161
|
+
|
|
162
|
+
const result = await validateToken(
|
|
163
|
+
token,
|
|
164
|
+
"https://example.com/.well-known/jwks",
|
|
165
|
+
{ audience: "test-client" },
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
expect(result).toBeDefined();
|
|
169
|
+
expect(result.payload.aud).toBe("test-client");
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it("should reject token with mismatched audience", async () => {
|
|
173
|
+
const { publicJWK, privateKey, kid } = await createTestJWKS("RS256");
|
|
174
|
+
const token = await createSignedToken(privateKey, "RS256", kid);
|
|
175
|
+
mockJWKSResponse(publicJWK);
|
|
176
|
+
|
|
177
|
+
await expect(
|
|
178
|
+
validateToken(token, "https://example.com/.well-known/jwks", {
|
|
179
|
+
audience: "wrong-client",
|
|
180
|
+
}),
|
|
181
|
+
).rejects.toThrow();
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it("should verify token with matching issuer", async () => {
|
|
185
|
+
const { publicJWK, privateKey, kid } = await createTestJWKS("RS256");
|
|
186
|
+
const token = await createSignedToken(privateKey, "RS256", kid);
|
|
187
|
+
mockJWKSResponse(publicJWK);
|
|
188
|
+
|
|
189
|
+
const result = await validateToken(
|
|
190
|
+
token,
|
|
191
|
+
"https://example.com/.well-known/jwks",
|
|
192
|
+
{ issuer: "https://example.com" },
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
expect(result).toBeDefined();
|
|
196
|
+
expect(result.payload.iss).toBe("https://example.com");
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it("should reject token with mismatched issuer", async () => {
|
|
200
|
+
const { publicJWK, privateKey, kid } = await createTestJWKS("RS256");
|
|
201
|
+
const token = await createSignedToken(privateKey, "RS256", kid);
|
|
202
|
+
mockJWKSResponse(publicJWK);
|
|
203
|
+
|
|
204
|
+
await expect(
|
|
205
|
+
validateToken(token, "https://example.com/.well-known/jwks", {
|
|
206
|
+
issuer: "https://wrong-issuer.com",
|
|
207
|
+
}),
|
|
208
|
+
).rejects.toThrow();
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
it("should verify token with both audience and issuer", async () => {
|
|
212
|
+
const { publicJWK, privateKey, kid } = await createTestJWKS("RS256");
|
|
213
|
+
const token = await createSignedToken(privateKey, "RS256", kid);
|
|
214
|
+
mockJWKSResponse(publicJWK);
|
|
215
|
+
|
|
216
|
+
const result = await validateToken(
|
|
217
|
+
token,
|
|
218
|
+
"https://example.com/.well-known/jwks",
|
|
219
|
+
{
|
|
220
|
+
audience: "test-client",
|
|
221
|
+
issuer: "https://example.com",
|
|
222
|
+
},
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
expect(result).toBeDefined();
|
|
226
|
+
expect(result.payload.aud).toBe("test-client");
|
|
227
|
+
expect(result.payload.iss).toBe("https://example.com");
|
|
228
|
+
});
|
|
229
|
+
});
|
|
@@ -112,41 +112,41 @@ export const apple = (options: AppleOptions) => {
|
|
|
112
112
|
if (options.verifyIdToken) {
|
|
113
113
|
return options.verifyIdToken(token, nonce);
|
|
114
114
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
jwtClaims[field]
|
|
115
|
+
try {
|
|
116
|
+
const decodedHeader = decodeProtectedHeader(token);
|
|
117
|
+
const { kid, alg: jwtAlg } = decodedHeader;
|
|
118
|
+
if (!kid || !jwtAlg) return false;
|
|
119
|
+
const publicKey = await getApplePublicKey(kid);
|
|
120
|
+
const { payload: jwtClaims } = await jwtVerify(token, publicKey, {
|
|
121
|
+
algorithms: [jwtAlg],
|
|
122
|
+
issuer: "https://appleid.apple.com",
|
|
123
|
+
audience:
|
|
124
|
+
options.audience && options.audience.length
|
|
125
|
+
? options.audience
|
|
126
|
+
: options.appBundleIdentifier
|
|
127
|
+
? options.appBundleIdentifier
|
|
128
|
+
: options.clientId,
|
|
129
|
+
maxTokenAge: "1h",
|
|
130
|
+
});
|
|
131
|
+
["email_verified", "is_private_email"].forEach((field) => {
|
|
132
|
+
if (jwtClaims[field] !== undefined) {
|
|
133
|
+
jwtClaims[field] = Boolean(jwtClaims[field]);
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
if (nonce && jwtClaims.nonce !== nonce) {
|
|
137
|
+
return false;
|
|
133
138
|
}
|
|
134
|
-
|
|
135
|
-
|
|
139
|
+
return !!jwtClaims;
|
|
140
|
+
} catch {
|
|
136
141
|
return false;
|
|
137
142
|
}
|
|
138
|
-
return !!jwtClaims;
|
|
139
143
|
},
|
|
140
144
|
refreshAccessToken: options.refreshAccessToken
|
|
141
145
|
? options.refreshAccessToken
|
|
142
146
|
: async (refreshToken) => {
|
|
143
147
|
return refreshAccessToken({
|
|
144
148
|
refreshToken,
|
|
145
|
-
options
|
|
146
|
-
clientId: options.clientId,
|
|
147
|
-
clientKey: options.clientKey,
|
|
148
|
-
clientSecret: options.clientSecret,
|
|
149
|
-
},
|
|
149
|
+
options,
|
|
150
150
|
tokenEndpoint: "https://appleid.apple.com/auth/token",
|
|
151
151
|
});
|
|
152
152
|
},
|
|
@@ -161,9 +161,18 @@ export const apple = (options: AppleOptions) => {
|
|
|
161
161
|
if (!profile) {
|
|
162
162
|
return null;
|
|
163
163
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
164
|
+
|
|
165
|
+
// TODO: "" masking will be removed when the name field is made optional
|
|
166
|
+
let name: string;
|
|
167
|
+
if (token.user?.name) {
|
|
168
|
+
const firstName = token.user.name.firstName || "";
|
|
169
|
+
const lastName = token.user.name.lastName || "";
|
|
170
|
+
const fullName = `${firstName} ${lastName}`.trim();
|
|
171
|
+
name = fullName;
|
|
172
|
+
} else {
|
|
173
|
+
name = profile.name || "";
|
|
174
|
+
}
|
|
175
|
+
|
|
167
176
|
const emailVerified =
|
|
168
177
|
typeof profile.email_verified === "boolean"
|
|
169
178
|
? profile.email_verified
|
|
@@ -178,10 +178,7 @@ export const cognito = (options: CognitoOptions) => {
|
|
|
178
178
|
return null;
|
|
179
179
|
}
|
|
180
180
|
const name =
|
|
181
|
-
profile.name ||
|
|
182
|
-
profile.given_name ||
|
|
183
|
-
profile.username ||
|
|
184
|
-
profile.email;
|
|
181
|
+
profile.name || profile.given_name || profile.username || "";
|
|
185
182
|
const enrichedProfile = {
|
|
186
183
|
...profile,
|
|
187
184
|
name,
|
|
@@ -220,7 +217,11 @@ export const cognito = (options: CognitoOptions) => {
|
|
|
220
217
|
return {
|
|
221
218
|
user: {
|
|
222
219
|
id: userInfo.sub,
|
|
223
|
-
name:
|
|
220
|
+
name:
|
|
221
|
+
userInfo.name ||
|
|
222
|
+
userInfo.given_name ||
|
|
223
|
+
userInfo.username ||
|
|
224
|
+
"",
|
|
224
225
|
email: userInfo.email,
|
|
225
226
|
image: userInfo.picture,
|
|
226
227
|
emailVerified: userInfo.email_verified,
|
|
@@ -49,7 +49,7 @@ export const facebook = (options: FacebookOptions) => {
|
|
|
49
49
|
return await createAuthorizationURL({
|
|
50
50
|
id: "facebook",
|
|
51
51
|
options,
|
|
52
|
-
authorizationEndpoint: "https://www.facebook.com/
|
|
52
|
+
authorizationEndpoint: "https://www.facebook.com/v24.0/dialog/oauth",
|
|
53
53
|
scopes: _scopes,
|
|
54
54
|
state,
|
|
55
55
|
redirectURI,
|
|
@@ -66,7 +66,7 @@ export const facebook = (options: FacebookOptions) => {
|
|
|
66
66
|
code,
|
|
67
67
|
redirectURI,
|
|
68
68
|
options,
|
|
69
|
-
tokenEndpoint: "https://graph.facebook.com/oauth/access_token",
|
|
69
|
+
tokenEndpoint: "https://graph.facebook.com/v24.0/oauth/access_token",
|
|
70
70
|
});
|
|
71
71
|
},
|
|
72
72
|
async verifyIdToken(token, nonce) {
|
|
@@ -121,7 +121,7 @@ export const facebook = (options: FacebookOptions) => {
|
|
|
121
121
|
clientSecret: options.clientSecret,
|
|
122
122
|
},
|
|
123
123
|
tokenEndpoint:
|
|
124
|
-
"https://graph.facebook.com/
|
|
124
|
+
"https://graph.facebook.com/v24.0/oauth/access_token",
|
|
125
125
|
});
|
|
126
126
|
},
|
|
127
127
|
async getUserInfo(token) {
|
|
@@ -34,7 +34,7 @@ export const figma = (options: FigmaOptions) => {
|
|
|
34
34
|
throw new BetterAuthError("codeVerifier is required for Figma");
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
const _scopes = options.disableDefaultScope ? [] : ["
|
|
37
|
+
const _scopes = options.disableDefaultScope ? [] : ["current_user:read"];
|
|
38
38
|
if (options.scope) _scopes.push(...options.scope);
|
|
39
39
|
if (scopes) _scopes.push(...scopes);
|
|
40
40
|
|
|
@@ -56,7 +56,8 @@ export const figma = (options: FigmaOptions) => {
|
|
|
56
56
|
codeVerifier,
|
|
57
57
|
redirectURI,
|
|
58
58
|
options,
|
|
59
|
-
tokenEndpoint: "https://
|
|
59
|
+
tokenEndpoint: "https://api.figma.com/v1/oauth/token",
|
|
60
|
+
authentication: "basic",
|
|
60
61
|
});
|
|
61
62
|
},
|
|
62
63
|
refreshAccessToken: options.refreshAccessToken
|
|
@@ -69,7 +70,8 @@ export const figma = (options: FigmaOptions) => {
|
|
|
69
70
|
clientKey: options.clientKey,
|
|
70
71
|
clientSecret: options.clientSecret,
|
|
71
72
|
},
|
|
72
|
-
tokenEndpoint: "https://
|
|
73
|
+
tokenEndpoint: "https://api.figma.com/v1/oauth/token",
|
|
74
|
+
authentication: "basic",
|
|
73
75
|
});
|
|
74
76
|
},
|
|
75
77
|
async getUserInfo(token) {
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { betterFetch } from "@better-fetch/fetch";
|
|
2
|
+
import { logger } from "../env";
|
|
2
3
|
import type { OAuthProvider, ProviderOptions } from "../oauth2";
|
|
3
4
|
import {
|
|
4
5
|
createAuthorizationURL,
|
|
6
|
+
getOAuth2Tokens,
|
|
5
7
|
refreshAccessToken,
|
|
6
|
-
validateAuthorizationCode,
|
|
7
8
|
} from "../oauth2";
|
|
9
|
+
import { createAuthorizationCodeRequest } from "../oauth2/validate-authorization-code";
|
|
8
10
|
|
|
9
11
|
export interface GithubProfile {
|
|
10
12
|
login: string;
|
|
@@ -86,13 +88,33 @@ export const github = (options: GithubOptions) => {
|
|
|
86
88
|
});
|
|
87
89
|
},
|
|
88
90
|
validateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {
|
|
89
|
-
|
|
91
|
+
const { body, headers: requestHeaders } = createAuthorizationCodeRequest({
|
|
90
92
|
code,
|
|
91
93
|
codeVerifier,
|
|
92
94
|
redirectURI,
|
|
93
95
|
options,
|
|
94
|
-
tokenEndpoint,
|
|
95
96
|
});
|
|
97
|
+
|
|
98
|
+
const { data, error } = await betterFetch<
|
|
99
|
+
| { access_token: string; token_type: string; scope: string }
|
|
100
|
+
| { error: string; error_description?: string; error_uri?: string }
|
|
101
|
+
>(tokenEndpoint, {
|
|
102
|
+
method: "POST",
|
|
103
|
+
body: body,
|
|
104
|
+
headers: requestHeaders,
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
if (error) {
|
|
108
|
+
logger.error("GitHub OAuth token exchange failed:", error);
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if ("error" in data) {
|
|
113
|
+
logger.error("GitHub OAuth token exchange failed:", data);
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return getOAuth2Tokens(data);
|
|
96
118
|
},
|
|
97
119
|
refreshAccessToken: options.refreshAccessToken
|
|
98
120
|
? options.refreshAccessToken
|
|
@@ -148,7 +170,7 @@ export const github = (options: GithubOptions) => {
|
|
|
148
170
|
return {
|
|
149
171
|
user: {
|
|
150
172
|
id: profile.id,
|
|
151
|
-
name: profile.name || profile.login,
|
|
173
|
+
name: profile.name || profile.login || "",
|
|
152
174
|
email: profile.email,
|
|
153
175
|
image: profile.avatar_url,
|
|
154
176
|
emailVerified,
|
|
@@ -65,7 +65,7 @@ const cleanDoubleSlashes = (input: string = "") => {
|
|
|
65
65
|
};
|
|
66
66
|
|
|
67
67
|
const issuerToEndpoints = (issuer?: string | undefined) => {
|
|
68
|
-
|
|
68
|
+
const baseUrl = issuer || "https://gitlab.com";
|
|
69
69
|
return {
|
|
70
70
|
authorizationEndpoint: cleanDoubleSlashes(`${baseUrl}/oauth/authorize`),
|
|
71
71
|
tokenEndpoint: cleanDoubleSlashes(`${baseUrl}/oauth/token`),
|
|
@@ -141,7 +141,7 @@ export const gitlab = (options: GitlabOptions) => {
|
|
|
141
141
|
return {
|
|
142
142
|
user: {
|
|
143
143
|
id: profile.id,
|
|
144
|
-
name: profile.name ?? profile.username,
|
|
144
|
+
name: profile.name ?? profile.username ?? "",
|
|
145
145
|
email: profile.email,
|
|
146
146
|
image: profile.avatar_url,
|
|
147
147
|
emailVerified: profile.email_verified ?? false,
|