@better-auth/core 1.7.0-beta.4 → 1.7.0-beta.6
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 +47 -4
- package/dist/api/index.mjs +40 -1
- 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 +57 -31
- package/dist/db/adapter/index.d.mts +54 -10
- package/dist/db/adapter/types.d.mts +1 -1
- package/dist/db/get-tables.mjs +3 -3
- package/dist/db/schema/account.d.mts +1 -1
- package/dist/db/schema/account.mjs +1 -1
- package/dist/db/type.d.mts +12 -7
- package/dist/env/env-impl.mjs +1 -1
- package/dist/error/codes.d.mts +5 -0
- package/dist/error/codes.mjs +5 -0
- package/dist/index.d.mts +2 -2
- package/dist/instrumentation/tracer.mjs +1 -1
- package/dist/oauth2/create-authorization-url.d.mts +4 -1
- package/dist/oauth2/create-authorization-url.mjs +5 -2
- package/dist/oauth2/dpop.d.mts +142 -0
- package/dist/oauth2/dpop.mjs +246 -0
- package/dist/oauth2/index.d.mts +6 -3
- package/dist/oauth2/index.mjs +5 -2
- package/dist/oauth2/oauth-provider.d.mts +128 -9
- package/dist/oauth2/refresh-access-token.mjs +1 -1
- package/dist/oauth2/scopes.d.mts +76 -0
- package/dist/oauth2/scopes.mjs +96 -0
- package/dist/oauth2/utils.mjs +2 -1
- package/dist/oauth2/verify-id-token.d.mts +26 -0
- package/dist/oauth2/verify-id-token.mjs +62 -0
- package/dist/oauth2/verify.d.mts +88 -15
- package/dist/oauth2/verify.mjs +187 -19
- package/dist/social-providers/apple.d.mts +14 -2
- package/dist/social-providers/apple.mjs +12 -36
- package/dist/social-providers/atlassian.d.mts +5 -1
- package/dist/social-providers/atlassian.mjs +4 -4
- package/dist/social-providers/cognito.d.mts +13 -2
- package/dist/social-providers/cognito.mjs +24 -32
- package/dist/social-providers/discord.d.mts +5 -1
- package/dist/social-providers/discord.mjs +7 -6
- package/dist/social-providers/dropbox.d.mts +5 -1
- package/dist/social-providers/dropbox.mjs +5 -5
- package/dist/social-providers/facebook.d.mts +21 -2
- package/dist/social-providers/facebook.mjs +46 -22
- package/dist/social-providers/figma.d.mts +5 -1
- package/dist/social-providers/figma.mjs +5 -5
- package/dist/social-providers/github.d.mts +5 -1
- package/dist/social-providers/github.mjs +4 -4
- package/dist/social-providers/gitlab.d.mts +5 -1
- package/dist/social-providers/gitlab.mjs +6 -6
- package/dist/social-providers/google.d.mts +29 -3
- package/dist/social-providers/google.mjs +24 -30
- package/dist/social-providers/huggingface.d.mts +5 -1
- package/dist/social-providers/huggingface.mjs +8 -8
- package/dist/social-providers/index.d.mts +222 -42
- package/dist/social-providers/kakao.d.mts +5 -1
- package/dist/social-providers/kakao.mjs +8 -8
- package/dist/social-providers/kick.d.mts +5 -1
- package/dist/social-providers/kick.mjs +4 -4
- package/dist/social-providers/line.d.mts +8 -2
- package/dist/social-providers/line.mjs +12 -14
- package/dist/social-providers/linear.d.mts +5 -1
- package/dist/social-providers/linear.mjs +4 -4
- package/dist/social-providers/linkedin.d.mts +5 -1
- package/dist/social-providers/linkedin.mjs +10 -10
- package/dist/social-providers/microsoft-entra-id.d.mts +41 -6
- package/dist/social-providers/microsoft-entra-id.mjs +40 -36
- package/dist/social-providers/naver.d.mts +5 -1
- package/dist/social-providers/naver.mjs +4 -4
- package/dist/social-providers/notion.d.mts +5 -1
- package/dist/social-providers/notion.mjs +4 -4
- package/dist/social-providers/paybin.d.mts +5 -1
- package/dist/social-providers/paybin.mjs +10 -10
- package/dist/social-providers/paypal.d.mts +5 -2
- package/dist/social-providers/paypal.mjs +8 -13
- package/dist/social-providers/polar.d.mts +5 -1
- package/dist/social-providers/polar.mjs +8 -8
- package/dist/social-providers/railway.d.mts +5 -1
- package/dist/social-providers/railway.mjs +9 -9
- package/dist/social-providers/reddit.d.mts +5 -1
- package/dist/social-providers/reddit.mjs +9 -8
- package/dist/social-providers/roblox.d.mts +5 -1
- package/dist/social-providers/roblox.mjs +5 -5
- package/dist/social-providers/salesforce.d.mts +5 -1
- package/dist/social-providers/salesforce.mjs +8 -8
- package/dist/social-providers/slack.d.mts +5 -1
- package/dist/social-providers/slack.mjs +9 -9
- package/dist/social-providers/spotify.d.mts +5 -1
- package/dist/social-providers/spotify.mjs +5 -5
- package/dist/social-providers/tiktok.d.mts +5 -1
- package/dist/social-providers/tiktok.mjs +9 -5
- package/dist/social-providers/twitch.d.mts +5 -1
- package/dist/social-providers/twitch.mjs +4 -4
- package/dist/social-providers/twitter.d.mts +6 -4
- package/dist/social-providers/twitter.mjs +9 -9
- package/dist/social-providers/vercel.d.mts +5 -1
- package/dist/social-providers/vercel.mjs +4 -7
- package/dist/social-providers/vk.d.mts +5 -1
- package/dist/social-providers/vk.mjs +5 -5
- package/dist/social-providers/wechat.d.mts +5 -1
- package/dist/social-providers/wechat.mjs +10 -6
- package/dist/social-providers/zoom.d.mts +6 -1
- package/dist/social-providers/zoom.mjs +15 -9
- package/dist/types/context.d.mts +27 -8
- package/dist/types/index.d.mts +1 -1
- package/dist/types/init-options.d.mts +137 -6
- package/dist/types/plugin-client.d.mts +12 -2
- package/dist/utils/host.mjs +4 -0
- package/dist/utils/url.mjs +4 -3
- package/package.json +7 -7
- package/src/api/index.ts +82 -0
- package/src/context/transaction.ts +45 -12
- package/src/db/adapter/factory.ts +127 -64
- package/src/db/adapter/index.ts +54 -9
- package/src/db/adapter/types.ts +1 -0
- package/src/db/get-tables.ts +8 -3
- package/src/db/schema/account.ts +14 -2
- package/src/db/type.ts +12 -7
- package/src/env/env-impl.ts +1 -2
- package/src/error/codes.ts +5 -0
- package/src/oauth2/create-authorization-url.ts +2 -2
- package/src/oauth2/dpop.ts +568 -0
- package/src/oauth2/index.ts +61 -2
- package/src/oauth2/oauth-provider.ts +140 -10
- package/src/oauth2/refresh-access-token.ts +2 -2
- package/src/oauth2/scopes.ts +118 -0
- package/src/oauth2/utils.ts +2 -5
- package/src/oauth2/verify-id-token.ts +111 -0
- package/src/oauth2/verify.ts +372 -58
- package/src/social-providers/apple.ts +24 -61
- package/src/social-providers/atlassian.ts +12 -8
- package/src/social-providers/cognito.ts +25 -47
- package/src/social-providers/discord.ts +19 -8
- package/src/social-providers/dropbox.ts +13 -7
- package/src/social-providers/facebook.ts +97 -51
- package/src/social-providers/figma.ts +13 -9
- package/src/social-providers/github.ts +12 -8
- package/src/social-providers/gitlab.ts +14 -8
- package/src/social-providers/google.ts +66 -47
- package/src/social-providers/huggingface.ts +12 -8
- package/src/social-providers/kakao.ts +16 -8
- package/src/social-providers/kick.ts +12 -7
- package/src/social-providers/line.ts +37 -37
- package/src/social-providers/linear.ts +12 -6
- package/src/social-providers/linkedin.ts +14 -10
- package/src/social-providers/microsoft-entra-id.ts +103 -59
- package/src/social-providers/naver.ts +12 -6
- package/src/social-providers/notion.ts +12 -6
- package/src/social-providers/paybin.ts +14 -11
- package/src/social-providers/paypal.ts +6 -25
- package/src/social-providers/polar.ts +12 -8
- package/src/social-providers/railway.ts +13 -9
- package/src/social-providers/reddit.ts +25 -10
- package/src/social-providers/roblox.ts +18 -7
- package/src/social-providers/salesforce.ts +12 -8
- package/src/social-providers/slack.ts +18 -9
- package/src/social-providers/spotify.ts +13 -7
- package/src/social-providers/tiktok.ts +13 -7
- package/src/social-providers/twitch.ts +12 -8
- package/src/social-providers/twitter.ts +17 -8
- package/src/social-providers/vercel.ts +16 -10
- package/src/social-providers/vk.ts +13 -7
- package/src/social-providers/wechat.ts +28 -9
- package/src/social-providers/zoom.ts +19 -6
- package/src/types/context.ts +26 -8
- package/src/types/index.ts +7 -0
- package/src/types/init-options.ts +159 -8
- package/src/types/plugin-client.ts +16 -2
- package/src/utils/host.ts +15 -0
- package/src/utils/url.ts +10 -4
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { betterFetch } from "@better-fetch/fetch";
|
|
2
|
-
import type {
|
|
2
|
+
import type { ProviderOptions, UpstreamProvider } from "../oauth2";
|
|
3
3
|
import {
|
|
4
4
|
createAuthorizationURL,
|
|
5
5
|
refreshAccessToken,
|
|
6
|
+
resolveRequestedScopes,
|
|
6
7
|
validateAuthorizationCode,
|
|
7
8
|
} from "../oauth2";
|
|
8
9
|
|
|
@@ -36,20 +37,30 @@ export interface RobloxOptions extends ProviderOptions<RobloxProfile> {
|
|
|
36
37
|
| undefined;
|
|
37
38
|
}
|
|
38
39
|
|
|
40
|
+
const ROBLOX_DEFAULT_SCOPES = ["openid", "profile"];
|
|
41
|
+
|
|
39
42
|
export const roblox = (options: RobloxOptions) => {
|
|
40
43
|
const tokenEndpoint = "https://apis.roblox.com/oauth/v1/token";
|
|
41
44
|
return {
|
|
42
45
|
id: "roblox",
|
|
43
46
|
name: "Roblox",
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
47
|
+
callbackPath: "/callback/roblox",
|
|
48
|
+
async createAuthorizationURL({
|
|
49
|
+
state,
|
|
50
|
+
scopes,
|
|
51
|
+
redirectURI,
|
|
52
|
+
additionalParams,
|
|
53
|
+
}) {
|
|
54
|
+
const requestedScopes = resolveRequestedScopes(
|
|
55
|
+
options,
|
|
56
|
+
ROBLOX_DEFAULT_SCOPES,
|
|
57
|
+
scopes,
|
|
58
|
+
);
|
|
48
59
|
return createAuthorizationURL({
|
|
49
60
|
id: "roblox",
|
|
50
61
|
options,
|
|
51
62
|
authorizationEndpoint: "https://apis.roblox.com/oauth/v1/authorize",
|
|
52
|
-
scopes:
|
|
63
|
+
scopes: requestedScopes,
|
|
53
64
|
state,
|
|
54
65
|
redirectURI,
|
|
55
66
|
prompt: options.prompt || "select_account consent",
|
|
@@ -113,5 +124,5 @@ export const roblox = (options: RobloxOptions) => {
|
|
|
113
124
|
};
|
|
114
125
|
},
|
|
115
126
|
options,
|
|
116
|
-
} satisfies
|
|
127
|
+
} satisfies UpstreamProvider<RobloxProfile>;
|
|
117
128
|
};
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { betterFetch } from "@better-fetch/fetch";
|
|
2
2
|
import { logger } from "../env";
|
|
3
3
|
import { BetterAuthError } from "../error";
|
|
4
|
-
import type {
|
|
4
|
+
import type { ProviderOptions, UpstreamProvider } from "../oauth2";
|
|
5
5
|
import {
|
|
6
6
|
createAuthorizationURL,
|
|
7
7
|
refreshAccessToken,
|
|
8
|
+
resolveRequestedScopes,
|
|
8
9
|
validateAuthorizationCode,
|
|
9
10
|
} from "../oauth2";
|
|
10
11
|
|
|
@@ -39,6 +40,8 @@ export interface SalesforceOptions extends ProviderOptions<SalesforceProfile> {
|
|
|
39
40
|
redirectURI?: string | undefined;
|
|
40
41
|
}
|
|
41
42
|
|
|
43
|
+
const SALESFORCE_DEFAULT_SCOPES = ["openid", "email", "profile"];
|
|
44
|
+
|
|
42
45
|
export const salesforce = (options: SalesforceOptions) => {
|
|
43
46
|
const environment = options.environment ?? "production";
|
|
44
47
|
const isSandbox = environment === "sandbox";
|
|
@@ -63,6 +66,7 @@ export const salesforce = (options: SalesforceOptions) => {
|
|
|
63
66
|
return {
|
|
64
67
|
id: "salesforce",
|
|
65
68
|
name: "Salesforce",
|
|
69
|
+
callbackPath: "/callback/salesforce",
|
|
66
70
|
|
|
67
71
|
async createAuthorizationURL({
|
|
68
72
|
state,
|
|
@@ -81,17 +85,17 @@ export const salesforce = (options: SalesforceOptions) => {
|
|
|
81
85
|
throw new BetterAuthError("codeVerifier is required for Salesforce");
|
|
82
86
|
}
|
|
83
87
|
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
88
|
+
const requestedScopes = resolveRequestedScopes(
|
|
89
|
+
options,
|
|
90
|
+
SALESFORCE_DEFAULT_SCOPES,
|
|
91
|
+
scopes,
|
|
92
|
+
);
|
|
89
93
|
|
|
90
94
|
return createAuthorizationURL({
|
|
91
95
|
id: "salesforce",
|
|
92
96
|
options,
|
|
93
97
|
authorizationEndpoint,
|
|
94
|
-
scopes:
|
|
98
|
+
scopes: requestedScopes,
|
|
95
99
|
state,
|
|
96
100
|
codeVerifier,
|
|
97
101
|
redirectURI: options.redirectURI || redirectURI,
|
|
@@ -162,5 +166,5 @@ export const salesforce = (options: SalesforceOptions) => {
|
|
|
162
166
|
},
|
|
163
167
|
|
|
164
168
|
options,
|
|
165
|
-
} satisfies
|
|
169
|
+
} satisfies UpstreamProvider<SalesforceProfile>;
|
|
166
170
|
};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { betterFetch } from "@better-fetch/fetch";
|
|
2
|
-
import type {
|
|
2
|
+
import type { ProviderOptions, UpstreamProvider } from "../oauth2";
|
|
3
3
|
import {
|
|
4
4
|
createAuthorizationURL,
|
|
5
5
|
refreshAccessToken,
|
|
6
|
+
resolveRequestedScopes,
|
|
6
7
|
validateAuthorizationCode,
|
|
7
8
|
} from "../oauth2";
|
|
8
9
|
|
|
@@ -41,22 +42,30 @@ export interface SlackOptions extends ProviderOptions<SlackProfile> {
|
|
|
41
42
|
clientId: string;
|
|
42
43
|
}
|
|
43
44
|
|
|
45
|
+
const SLACK_DEFAULT_SCOPES = ["openid", "profile", "email"];
|
|
46
|
+
|
|
44
47
|
export const slack = (options: SlackOptions) => {
|
|
45
48
|
const tokenEndpoint = "https://slack.com/api/openid.connect.token";
|
|
46
49
|
return {
|
|
47
50
|
id: "slack",
|
|
48
51
|
name: "Slack",
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
callbackPath: "/callback/slack",
|
|
53
|
+
async createAuthorizationURL({
|
|
54
|
+
state,
|
|
55
|
+
scopes,
|
|
56
|
+
redirectURI,
|
|
57
|
+
additionalParams,
|
|
58
|
+
}) {
|
|
59
|
+
const requestedScopes = resolveRequestedScopes(
|
|
60
|
+
options,
|
|
61
|
+
SLACK_DEFAULT_SCOPES,
|
|
62
|
+
scopes,
|
|
63
|
+
);
|
|
55
64
|
return createAuthorizationURL({
|
|
56
65
|
id: "slack",
|
|
57
66
|
options,
|
|
58
67
|
authorizationEndpoint: "https://slack.com/openid/connect/authorize",
|
|
59
|
-
scopes:
|
|
68
|
+
scopes: requestedScopes,
|
|
60
69
|
state,
|
|
61
70
|
redirectURI,
|
|
62
71
|
additionalParams,
|
|
@@ -114,5 +123,5 @@ export const slack = (options: SlackOptions) => {
|
|
|
114
123
|
};
|
|
115
124
|
},
|
|
116
125
|
options,
|
|
117
|
-
} satisfies
|
|
126
|
+
} satisfies UpstreamProvider<SlackProfile>;
|
|
118
127
|
};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { betterFetch } from "@better-fetch/fetch";
|
|
2
|
-
import type {
|
|
2
|
+
import type { ProviderOptions, UpstreamProvider } from "../oauth2";
|
|
3
3
|
import {
|
|
4
4
|
createAuthorizationURL,
|
|
5
5
|
refreshAccessToken,
|
|
6
|
+
resolveRequestedScopes,
|
|
6
7
|
validateAuthorizationCode,
|
|
7
8
|
} from "../oauth2";
|
|
8
9
|
|
|
@@ -19,26 +20,31 @@ export interface SpotifyOptions extends ProviderOptions<SpotifyProfile> {
|
|
|
19
20
|
clientId: string;
|
|
20
21
|
}
|
|
21
22
|
|
|
23
|
+
const SPOTIFY_DEFAULT_SCOPES = ["user-read-email"];
|
|
24
|
+
|
|
22
25
|
export const spotify = (options: SpotifyOptions) => {
|
|
23
26
|
const tokenEndpoint = "https://accounts.spotify.com/api/token";
|
|
24
27
|
return {
|
|
25
28
|
id: "spotify",
|
|
26
29
|
name: "Spotify",
|
|
27
|
-
|
|
30
|
+
callbackPath: "/callback/spotify",
|
|
31
|
+
async createAuthorizationURL({
|
|
28
32
|
state,
|
|
29
33
|
scopes,
|
|
30
34
|
codeVerifier,
|
|
31
35
|
redirectURI,
|
|
32
36
|
additionalParams,
|
|
33
37
|
}) {
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
38
|
+
const requestedScopes = resolveRequestedScopes(
|
|
39
|
+
options,
|
|
40
|
+
SPOTIFY_DEFAULT_SCOPES,
|
|
41
|
+
scopes,
|
|
42
|
+
);
|
|
37
43
|
return createAuthorizationURL({
|
|
38
44
|
id: "spotify",
|
|
39
45
|
options,
|
|
40
46
|
authorizationEndpoint: "https://accounts.spotify.com/authorize",
|
|
41
|
-
scopes:
|
|
47
|
+
scopes: requestedScopes,
|
|
42
48
|
state,
|
|
43
49
|
codeVerifier,
|
|
44
50
|
redirectURI,
|
|
@@ -97,5 +103,5 @@ export const spotify = (options: SpotifyOptions) => {
|
|
|
97
103
|
};
|
|
98
104
|
},
|
|
99
105
|
options,
|
|
100
|
-
} satisfies
|
|
106
|
+
} satisfies UpstreamProvider<SpotifyProfile>;
|
|
101
107
|
};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { betterFetch } from "@better-fetch/fetch";
|
|
2
|
-
import type {
|
|
2
|
+
import type { ProviderOptions, UpstreamProvider } from "../oauth2";
|
|
3
3
|
import {
|
|
4
4
|
RESERVED_AUTHORIZATION_PARAMS_SET,
|
|
5
5
|
refreshAccessToken,
|
|
6
|
+
resolveRequestedScopes,
|
|
6
7
|
validateAuthorizationCode,
|
|
7
8
|
} from "../oauth2";
|
|
8
9
|
|
|
@@ -130,19 +131,24 @@ export interface TiktokOptions extends ProviderOptions {
|
|
|
130
131
|
clientKey: string;
|
|
131
132
|
}
|
|
132
133
|
|
|
134
|
+
const TIKTOK_DEFAULT_SCOPES = ["user.info.profile"];
|
|
135
|
+
|
|
133
136
|
export const tiktok = (options: TiktokOptions) => {
|
|
134
137
|
const tokenEndpoint = "https://open.tiktokapis.com/v2/oauth/token/";
|
|
135
138
|
return {
|
|
136
139
|
id: "tiktok",
|
|
137
140
|
name: "TikTok",
|
|
141
|
+
callbackPath: "/callback/tiktok",
|
|
138
142
|
createAuthorizationURL({ state, scopes, redirectURI, additionalParams }) {
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
|
|
143
|
+
const requestedScopes = resolveRequestedScopes(
|
|
144
|
+
options,
|
|
145
|
+
TIKTOK_DEFAULT_SCOPES,
|
|
146
|
+
scopes,
|
|
147
|
+
);
|
|
142
148
|
// TikTok uses `client_key` instead of the standard `client_id`, so the
|
|
143
149
|
// shared createAuthorizationURL helper cannot be used directly.
|
|
144
150
|
const url = new URL("https://www.tiktok.com/v2/auth/authorize");
|
|
145
|
-
url.searchParams.set("scope",
|
|
151
|
+
url.searchParams.set("scope", requestedScopes.join(","));
|
|
146
152
|
url.searchParams.set("response_type", "code");
|
|
147
153
|
url.searchParams.set("client_key", options.clientKey);
|
|
148
154
|
url.searchParams.set("redirect_uri", options.redirectURI || redirectURI);
|
|
@@ -154,7 +160,7 @@ export const tiktok = (options: TiktokOptions) => {
|
|
|
154
160
|
url.searchParams.set(key, value);
|
|
155
161
|
}
|
|
156
162
|
}
|
|
157
|
-
return url;
|
|
163
|
+
return { url, requestedScopes };
|
|
158
164
|
},
|
|
159
165
|
|
|
160
166
|
validateAuthorizationCode: async ({ code, redirectURI }) => {
|
|
@@ -220,5 +226,5 @@ export const tiktok = (options: TiktokOptions) => {
|
|
|
220
226
|
};
|
|
221
227
|
},
|
|
222
228
|
options,
|
|
223
|
-
} satisfies
|
|
229
|
+
} satisfies UpstreamProvider<TiktokProfile, TiktokOptions>;
|
|
224
230
|
};
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { decodeJwt } from "jose";
|
|
2
2
|
import { logger } from "../env";
|
|
3
|
-
import type {
|
|
3
|
+
import type { ProviderOptions, UpstreamProvider } from "../oauth2";
|
|
4
4
|
import {
|
|
5
5
|
createAuthorizationURL,
|
|
6
6
|
refreshAccessToken,
|
|
7
|
+
resolveRequestedScopes,
|
|
7
8
|
validateAuthorizationCode,
|
|
8
9
|
} from "../oauth2";
|
|
9
10
|
|
|
@@ -37,23 +38,26 @@ export interface TwitchOptions extends ProviderOptions<TwitchProfile> {
|
|
|
37
38
|
clientId: string;
|
|
38
39
|
claims?: string[] | undefined;
|
|
39
40
|
}
|
|
41
|
+
const TWITCH_DEFAULT_SCOPES = ["user:read:email", "openid"];
|
|
42
|
+
|
|
40
43
|
export const twitch = (options: TwitchOptions) => {
|
|
41
44
|
const tokenEndpoint = "https://id.twitch.tv/oauth2/token";
|
|
42
45
|
return {
|
|
43
46
|
id: "twitch",
|
|
44
47
|
name: "Twitch",
|
|
48
|
+
callbackPath: "/callback/twitch",
|
|
45
49
|
createAuthorizationURL({ state, scopes, redirectURI, additionalParams }) {
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
50
|
+
const requestedScopes = resolveRequestedScopes(
|
|
51
|
+
options,
|
|
52
|
+
TWITCH_DEFAULT_SCOPES,
|
|
53
|
+
scopes,
|
|
54
|
+
);
|
|
51
55
|
return createAuthorizationURL({
|
|
52
56
|
id: "twitch",
|
|
53
57
|
redirectURI,
|
|
54
58
|
options,
|
|
55
59
|
authorizationEndpoint: "https://id.twitch.tv/oauth2/authorize",
|
|
56
|
-
scopes:
|
|
60
|
+
scopes: requestedScopes,
|
|
57
61
|
state,
|
|
58
62
|
claims: options.claims || [
|
|
59
63
|
"email",
|
|
@@ -109,5 +113,5 @@ export const twitch = (options: TwitchOptions) => {
|
|
|
109
113
|
};
|
|
110
114
|
},
|
|
111
115
|
options,
|
|
112
|
-
} satisfies
|
|
116
|
+
} satisfies UpstreamProvider<TwitchProfile>;
|
|
113
117
|
};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { betterFetch } from "@better-fetch/fetch";
|
|
2
|
-
import type {
|
|
2
|
+
import type { ProviderOptions, UpstreamProvider } from "../oauth2";
|
|
3
3
|
import {
|
|
4
4
|
createAuthorizationURL,
|
|
5
5
|
refreshAccessToken,
|
|
6
|
+
resolveRequestedScopes,
|
|
6
7
|
validateAuthorizationCode,
|
|
7
8
|
} from "../oauth2";
|
|
8
9
|
|
|
@@ -103,22 +104,30 @@ export interface TwitterOption extends ProviderOptions<TwitterProfile> {
|
|
|
103
104
|
clientId: string;
|
|
104
105
|
}
|
|
105
106
|
|
|
107
|
+
const TWITTER_DEFAULT_SCOPES = [
|
|
108
|
+
"users.read",
|
|
109
|
+
"tweet.read",
|
|
110
|
+
"offline.access",
|
|
111
|
+
"users.email",
|
|
112
|
+
];
|
|
113
|
+
|
|
106
114
|
export const twitter = (options: TwitterOption) => {
|
|
107
115
|
const tokenEndpoint = "https://api.x.com/2/oauth2/token";
|
|
108
116
|
return {
|
|
109
117
|
id: "twitter",
|
|
110
118
|
name: "Twitter",
|
|
119
|
+
callbackPath: "/callback/twitter",
|
|
111
120
|
createAuthorizationURL(data) {
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
121
|
+
const requestedScopes = resolveRequestedScopes(
|
|
122
|
+
options,
|
|
123
|
+
TWITTER_DEFAULT_SCOPES,
|
|
124
|
+
data.scopes,
|
|
125
|
+
);
|
|
117
126
|
return createAuthorizationURL({
|
|
118
127
|
id: "twitter",
|
|
119
128
|
options,
|
|
120
129
|
authorizationEndpoint: "https://x.com/i/oauth2/authorize",
|
|
121
|
-
scopes:
|
|
130
|
+
scopes: requestedScopes,
|
|
122
131
|
state: data.state,
|
|
123
132
|
codeVerifier: data.codeVerifier,
|
|
124
133
|
redirectURI: data.redirectURI,
|
|
@@ -196,5 +205,5 @@ export const twitter = (options: TwitterOption) => {
|
|
|
196
205
|
};
|
|
197
206
|
},
|
|
198
207
|
options,
|
|
199
|
-
} satisfies
|
|
208
|
+
} satisfies UpstreamProvider<TwitterProfile>;
|
|
200
209
|
};
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { betterFetch } from "@better-fetch/fetch";
|
|
2
2
|
import { BetterAuthError } from "../error";
|
|
3
|
-
import type {
|
|
4
|
-
import {
|
|
3
|
+
import type { ProviderOptions, UpstreamProvider } from "../oauth2";
|
|
4
|
+
import {
|
|
5
|
+
createAuthorizationURL,
|
|
6
|
+
resolveRequestedScopes,
|
|
7
|
+
validateAuthorizationCode,
|
|
8
|
+
} from "../oauth2";
|
|
5
9
|
|
|
6
10
|
export interface VercelProfile {
|
|
7
11
|
sub: string;
|
|
@@ -16,10 +20,13 @@ export interface VercelOptions extends ProviderOptions<VercelProfile> {
|
|
|
16
20
|
clientId: string;
|
|
17
21
|
}
|
|
18
22
|
|
|
23
|
+
const VERCEL_DEFAULT_SCOPES: string[] = [];
|
|
24
|
+
|
|
19
25
|
export const vercel = (options: VercelOptions) => {
|
|
20
26
|
return {
|
|
21
27
|
id: "vercel",
|
|
22
28
|
name: "Vercel",
|
|
29
|
+
callbackPath: "/callback/vercel",
|
|
23
30
|
createAuthorizationURL({
|
|
24
31
|
state,
|
|
25
32
|
scopes,
|
|
@@ -31,18 +38,17 @@ export const vercel = (options: VercelOptions) => {
|
|
|
31
38
|
throw new BetterAuthError("codeVerifier is required for Vercel");
|
|
32
39
|
}
|
|
33
40
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
41
|
+
const requestedScopes = resolveRequestedScopes(
|
|
42
|
+
options,
|
|
43
|
+
VERCEL_DEFAULT_SCOPES,
|
|
44
|
+
scopes,
|
|
45
|
+
);
|
|
40
46
|
|
|
41
47
|
return createAuthorizationURL({
|
|
42
48
|
id: "vercel",
|
|
43
49
|
options,
|
|
44
50
|
authorizationEndpoint: "https://vercel.com/oauth/authorize",
|
|
45
|
-
scopes:
|
|
51
|
+
scopes: requestedScopes,
|
|
46
52
|
state,
|
|
47
53
|
codeVerifier,
|
|
48
54
|
redirectURI,
|
|
@@ -90,5 +96,5 @@ export const vercel = (options: VercelOptions) => {
|
|
|
90
96
|
};
|
|
91
97
|
},
|
|
92
98
|
options,
|
|
93
|
-
} satisfies
|
|
99
|
+
} satisfies UpstreamProvider<VercelProfile>;
|
|
94
100
|
};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { betterFetch } from "@better-fetch/fetch";
|
|
2
|
-
import type {
|
|
2
|
+
import type { ProviderOptions, UpstreamProvider } from "../oauth2";
|
|
3
3
|
import {
|
|
4
4
|
createAuthorizationURL,
|
|
5
5
|
refreshAccessToken,
|
|
6
|
+
resolveRequestedScopes,
|
|
6
7
|
validateAuthorizationCode,
|
|
7
8
|
} from "../oauth2";
|
|
8
9
|
|
|
@@ -25,28 +26,33 @@ export interface VkOption extends ProviderOptions {
|
|
|
25
26
|
scheme?: ("light" | "dark") | undefined;
|
|
26
27
|
}
|
|
27
28
|
|
|
29
|
+
const VK_DEFAULT_SCOPES = ["email", "phone"];
|
|
30
|
+
|
|
28
31
|
export const vk = (options: VkOption) => {
|
|
29
32
|
const tokenEndpoint = "https://id.vk.com/oauth2/auth";
|
|
30
33
|
return {
|
|
31
34
|
id: "vk",
|
|
32
35
|
name: "VK",
|
|
33
|
-
|
|
36
|
+
callbackPath: "/callback/vk",
|
|
37
|
+
createAuthorizationURL({
|
|
34
38
|
state,
|
|
35
39
|
scopes,
|
|
36
40
|
codeVerifier,
|
|
37
41
|
redirectURI,
|
|
38
42
|
additionalParams,
|
|
39
43
|
}) {
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
44
|
+
const requestedScopes = resolveRequestedScopes(
|
|
45
|
+
options,
|
|
46
|
+
VK_DEFAULT_SCOPES,
|
|
47
|
+
scopes,
|
|
48
|
+
);
|
|
43
49
|
const authorizationEndpoint = "https://id.vk.com/authorize";
|
|
44
50
|
|
|
45
51
|
return createAuthorizationURL({
|
|
46
52
|
id: "vk",
|
|
47
53
|
options,
|
|
48
54
|
authorizationEndpoint,
|
|
49
|
-
scopes:
|
|
55
|
+
scopes: requestedScopes,
|
|
50
56
|
state,
|
|
51
57
|
redirectURI,
|
|
52
58
|
codeVerifier,
|
|
@@ -128,5 +134,5 @@ export const vk = (options: VkOption) => {
|
|
|
128
134
|
};
|
|
129
135
|
},
|
|
130
136
|
options,
|
|
131
|
-
} satisfies
|
|
137
|
+
} satisfies UpstreamProvider<VkProfile>;
|
|
132
138
|
};
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { betterFetch } from "@better-fetch/fetch";
|
|
2
|
-
import type {
|
|
3
|
-
|
|
2
|
+
import type {
|
|
3
|
+
OAuth2Tokens,
|
|
4
|
+
ProviderOptions,
|
|
5
|
+
UpstreamProvider,
|
|
6
|
+
} from "../oauth2";
|
|
7
|
+
import {
|
|
8
|
+
RESERVED_AUTHORIZATION_PARAMS_SET,
|
|
9
|
+
resolveRequestedScopes,
|
|
10
|
+
} from "../oauth2";
|
|
4
11
|
|
|
5
12
|
/**
|
|
6
13
|
* WeChat user profile information
|
|
@@ -55,19 +62,24 @@ export interface WeChatOptions extends ProviderOptions<WeChatProfile> {
|
|
|
55
62
|
lang?: "cn" | "en";
|
|
56
63
|
}
|
|
57
64
|
|
|
65
|
+
const WECHAT_DEFAULT_SCOPES = ["snsapi_login"];
|
|
66
|
+
|
|
58
67
|
export const wechat = (options: WeChatOptions) => {
|
|
59
68
|
return {
|
|
60
69
|
id: "wechat",
|
|
61
70
|
name: "WeChat",
|
|
71
|
+
callbackPath: "/callback/wechat",
|
|
62
72
|
createAuthorizationURL({ state, scopes, redirectURI, additionalParams }) {
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
73
|
+
const requestedScopes = resolveRequestedScopes(
|
|
74
|
+
options,
|
|
75
|
+
WECHAT_DEFAULT_SCOPES,
|
|
76
|
+
scopes,
|
|
77
|
+
);
|
|
66
78
|
|
|
67
79
|
// WeChat uses non-standard OAuth2 parameters (appid instead of client_id)
|
|
68
80
|
// and requires a fragment (#wechat_redirect), so we construct the URL manually.
|
|
69
81
|
const url = new URL("https://open.weixin.qq.com/connect/qrconnect");
|
|
70
|
-
url.searchParams.set("scope",
|
|
82
|
+
url.searchParams.set("scope", requestedScopes.join(","));
|
|
71
83
|
url.searchParams.set("response_type", "code");
|
|
72
84
|
url.searchParams.set("appid", options.clientId);
|
|
73
85
|
url.searchParams.set("redirect_uri", options.redirectURI || redirectURI);
|
|
@@ -82,7 +94,7 @@ export const wechat = (options: WeChatOptions) => {
|
|
|
82
94
|
}
|
|
83
95
|
url.hash = "wechat_redirect";
|
|
84
96
|
|
|
85
|
-
return url;
|
|
97
|
+
return { url, requestedScopes };
|
|
86
98
|
},
|
|
87
99
|
|
|
88
100
|
// WeChat uses non-standard token exchange (appid/secret instead of
|
|
@@ -208,7 +220,14 @@ export const wechat = (options: WeChatOptions) => {
|
|
|
208
220
|
user: {
|
|
209
221
|
id: profile.unionid || profile.openid || openid,
|
|
210
222
|
name: profile.nickname,
|
|
211
|
-
|
|
223
|
+
// WeChat does not return an email, and the OAuth callback rejects a
|
|
224
|
+
// missing one, so the default sign-in would always fail. Synthesize a
|
|
225
|
+
// stable, non-routable placeholder (RFC 2606 `.invalid`) keyed to the
|
|
226
|
+
// user's WeChat id, left unverified. Applications that collect a real
|
|
227
|
+
// email override it via `mapProfileToUser`.
|
|
228
|
+
email:
|
|
229
|
+
profile.email ||
|
|
230
|
+
`${profile.unionid || profile.openid || openid}@wechat.invalid`,
|
|
212
231
|
image: profile.headimgurl,
|
|
213
232
|
emailVerified: false,
|
|
214
233
|
...userMap,
|
|
@@ -217,5 +236,5 @@ export const wechat = (options: WeChatOptions) => {
|
|
|
217
236
|
};
|
|
218
237
|
},
|
|
219
238
|
options,
|
|
220
|
-
} satisfies
|
|
239
|
+
} satisfies UpstreamProvider<WeChatProfile, WeChatOptions>;
|
|
221
240
|
};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { betterFetch } from "@better-fetch/fetch";
|
|
2
|
-
import type {
|
|
2
|
+
import type { ProviderOptions, UpstreamProvider } from "../oauth2";
|
|
3
3
|
import {
|
|
4
4
|
createAuthorizationURL,
|
|
5
5
|
refreshAccessToken,
|
|
6
|
+
resolveRequestedScopes,
|
|
6
7
|
validateAuthorizationCode,
|
|
7
8
|
} from "../oauth2";
|
|
8
9
|
|
|
@@ -143,6 +144,8 @@ export interface ZoomOptions extends ProviderOptions<ZoomProfile> {
|
|
|
143
144
|
pkce?: boolean | undefined;
|
|
144
145
|
}
|
|
145
146
|
|
|
147
|
+
const ZOOM_DEFAULT_SCOPES: string[] = [];
|
|
148
|
+
|
|
146
149
|
export const zoom = (userOptions: ZoomOptions) => {
|
|
147
150
|
const options = {
|
|
148
151
|
pkce: true,
|
|
@@ -152,21 +155,31 @@ export const zoom = (userOptions: ZoomOptions) => {
|
|
|
152
155
|
return {
|
|
153
156
|
id: "zoom",
|
|
154
157
|
name: "Zoom",
|
|
155
|
-
|
|
158
|
+
callbackPath: "/callback/zoom",
|
|
159
|
+
createAuthorizationURL: ({
|
|
156
160
|
state,
|
|
161
|
+
scopes,
|
|
157
162
|
redirectURI,
|
|
158
163
|
codeVerifier,
|
|
159
164
|
additionalParams,
|
|
160
|
-
}) =>
|
|
161
|
-
|
|
165
|
+
}) => {
|
|
166
|
+
const requestedScopes = resolveRequestedScopes(
|
|
167
|
+
options,
|
|
168
|
+
ZOOM_DEFAULT_SCOPES,
|
|
169
|
+
scopes,
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
return createAuthorizationURL({
|
|
162
173
|
id: "zoom",
|
|
163
174
|
options,
|
|
164
175
|
authorizationEndpoint: "https://zoom.us/oauth/authorize",
|
|
176
|
+
scopes: requestedScopes,
|
|
165
177
|
state,
|
|
166
178
|
redirectURI,
|
|
167
179
|
codeVerifier: options.pkce ? codeVerifier : undefined,
|
|
168
180
|
additionalParams,
|
|
169
|
-
})
|
|
181
|
+
});
|
|
182
|
+
},
|
|
170
183
|
validateAuthorizationCode: async ({ code, redirectURI, codeVerifier }) => {
|
|
171
184
|
return validateAuthorizationCode({
|
|
172
185
|
code,
|
|
@@ -222,5 +235,5 @@ export const zoom = (userOptions: ZoomOptions) => {
|
|
|
222
235
|
},
|
|
223
236
|
};
|
|
224
237
|
},
|
|
225
|
-
} satisfies
|
|
238
|
+
} satisfies UpstreamProvider<ZoomProfile>;
|
|
226
239
|
};
|