@better-auth/core 1.7.0-beta.1 → 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 +144 -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 +6 -2
- 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 +153 -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
|
@@ -44,7 +44,7 @@ export const naver = (options: NaverOptions) => {
|
|
|
44
44
|
return {
|
|
45
45
|
id: "naver",
|
|
46
46
|
name: "Naver",
|
|
47
|
-
createAuthorizationURL({ state, scopes, redirectURI }) {
|
|
47
|
+
createAuthorizationURL({ state, scopes, redirectURI, additionalParams }) {
|
|
48
48
|
const _scopes = options.disableDefaultScope ? [] : ["profile", "email"];
|
|
49
49
|
if (options.scope) _scopes.push(...options.scope);
|
|
50
50
|
if (scopes) _scopes.push(...scopes);
|
|
@@ -55,6 +55,7 @@ export const naver = (options: NaverOptions) => {
|
|
|
55
55
|
scopes: _scopes,
|
|
56
56
|
state,
|
|
57
57
|
redirectURI,
|
|
58
|
+
additionalParams,
|
|
58
59
|
});
|
|
59
60
|
},
|
|
60
61
|
validateAuthorizationCode: async ({ code, redirectURI }) => {
|
|
@@ -28,7 +28,13 @@ export const notion = (options: NotionOptions) => {
|
|
|
28
28
|
return {
|
|
29
29
|
id: "notion",
|
|
30
30
|
name: "Notion",
|
|
31
|
-
createAuthorizationURL({
|
|
31
|
+
createAuthorizationURL({
|
|
32
|
+
state,
|
|
33
|
+
scopes,
|
|
34
|
+
loginHint,
|
|
35
|
+
redirectURI,
|
|
36
|
+
additionalParams,
|
|
37
|
+
}) {
|
|
32
38
|
const _scopes: string[] = options.disableDefaultScope ? [] : [];
|
|
33
39
|
if (options.scope) _scopes.push(...options.scope);
|
|
34
40
|
if (scopes) _scopes.push(...scopes);
|
|
@@ -41,6 +47,7 @@ export const notion = (options: NotionOptions) => {
|
|
|
41
47
|
redirectURI,
|
|
42
48
|
loginHint,
|
|
43
49
|
additionalParams: {
|
|
50
|
+
...(additionalParams ?? {}),
|
|
44
51
|
owner: "user",
|
|
45
52
|
},
|
|
46
53
|
});
|
|
@@ -42,6 +42,7 @@ export const paybin = (options: PaybinOptions) => {
|
|
|
42
42
|
codeVerifier,
|
|
43
43
|
redirectURI,
|
|
44
44
|
loginHint,
|
|
45
|
+
additionalParams,
|
|
45
46
|
}) {
|
|
46
47
|
if (!options.clientId || !options.clientSecret) {
|
|
47
48
|
logger.error(
|
|
@@ -67,6 +68,7 @@ export const paybin = (options: PaybinOptions) => {
|
|
|
67
68
|
redirectURI,
|
|
68
69
|
prompt: options.prompt,
|
|
69
70
|
loginHint,
|
|
71
|
+
additionalParams,
|
|
70
72
|
});
|
|
71
73
|
return url;
|
|
72
74
|
},
|
|
@@ -7,6 +7,7 @@ import type { OAuthProvider, ProviderOptions } from "../oauth2";
|
|
|
7
7
|
import { createAuthorizationURL } from "../oauth2";
|
|
8
8
|
|
|
9
9
|
export interface PayPalProfile {
|
|
10
|
+
sub?: string | undefined;
|
|
10
11
|
user_id: string;
|
|
11
12
|
name: string;
|
|
12
13
|
given_name: string;
|
|
@@ -78,7 +79,12 @@ export const paypal = (options: PayPalOptions) => {
|
|
|
78
79
|
return {
|
|
79
80
|
id: "paypal",
|
|
80
81
|
name: "PayPal",
|
|
81
|
-
async createAuthorizationURL({
|
|
82
|
+
async createAuthorizationURL({
|
|
83
|
+
state,
|
|
84
|
+
codeVerifier,
|
|
85
|
+
redirectURI,
|
|
86
|
+
additionalParams,
|
|
87
|
+
}) {
|
|
82
88
|
if (!options.clientId || !options.clientSecret) {
|
|
83
89
|
logger.error(
|
|
84
90
|
"Client Id and Client Secret is required for PayPal. Make sure to provide them in the options.",
|
|
@@ -103,6 +109,7 @@ export const paypal = (options: PayPalOptions) => {
|
|
|
103
109
|
codeVerifier,
|
|
104
110
|
redirectURI,
|
|
105
111
|
prompt: options.prompt,
|
|
112
|
+
additionalParams,
|
|
106
113
|
});
|
|
107
114
|
return url;
|
|
108
115
|
},
|
|
@@ -194,22 +201,6 @@ export const paypal = (options: PayPalOptions) => {
|
|
|
194
201
|
}
|
|
195
202
|
},
|
|
196
203
|
|
|
197
|
-
async verifyIdToken(token, nonce) {
|
|
198
|
-
if (options.disableIdTokenSignIn) {
|
|
199
|
-
return false;
|
|
200
|
-
}
|
|
201
|
-
if (options.verifyIdToken) {
|
|
202
|
-
return options.verifyIdToken(token, nonce);
|
|
203
|
-
}
|
|
204
|
-
try {
|
|
205
|
-
const payload = decodeJwt(token);
|
|
206
|
-
return !!payload.sub;
|
|
207
|
-
} catch (error) {
|
|
208
|
-
logger.error("Failed to verify PayPal ID token:", error);
|
|
209
|
-
return false;
|
|
210
|
-
}
|
|
211
|
-
},
|
|
212
|
-
|
|
213
204
|
async getUserInfo(token) {
|
|
214
205
|
if (options.getUserInfo) {
|
|
215
206
|
return options.getUserInfo(token);
|
|
@@ -237,6 +228,26 @@ export const paypal = (options: PayPalOptions) => {
|
|
|
237
228
|
}
|
|
238
229
|
|
|
239
230
|
const userInfo = response.data;
|
|
231
|
+
if (token.idToken) {
|
|
232
|
+
let idTokenSubject: string | undefined;
|
|
233
|
+
try {
|
|
234
|
+
idTokenSubject = decodeJwt(token.idToken).sub;
|
|
235
|
+
} catch (error) {
|
|
236
|
+
logger.error("Failed to decode PayPal ID token:", error);
|
|
237
|
+
return null;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// OIDC binds UserInfo to the ID Token with `sub`. Keep `user_id`
|
|
241
|
+
// as the account id below for existing PayPal account mappings.
|
|
242
|
+
const userInfoSubject = userInfo.sub ?? userInfo.user_id;
|
|
243
|
+
if (!idTokenSubject || userInfoSubject !== idTokenSubject) {
|
|
244
|
+
logger.error(
|
|
245
|
+
"PayPal user info subject does not match ID token subject",
|
|
246
|
+
);
|
|
247
|
+
return null;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
240
251
|
const userMap = await options.mapProfileToUser?.(userInfo);
|
|
241
252
|
|
|
242
253
|
const result = {
|
|
@@ -37,7 +37,13 @@ export const polar = (options: PolarOptions) => {
|
|
|
37
37
|
return {
|
|
38
38
|
id: "polar",
|
|
39
39
|
name: "Polar",
|
|
40
|
-
createAuthorizationURL({
|
|
40
|
+
createAuthorizationURL({
|
|
41
|
+
state,
|
|
42
|
+
scopes,
|
|
43
|
+
codeVerifier,
|
|
44
|
+
redirectURI,
|
|
45
|
+
additionalParams,
|
|
46
|
+
}) {
|
|
41
47
|
const _scopes = options.disableDefaultScope
|
|
42
48
|
? []
|
|
43
49
|
: ["openid", "profile", "email"];
|
|
@@ -52,6 +58,7 @@ export const polar = (options: PolarOptions) => {
|
|
|
52
58
|
codeVerifier,
|
|
53
59
|
redirectURI,
|
|
54
60
|
prompt: options.prompt,
|
|
61
|
+
additionalParams,
|
|
55
62
|
});
|
|
56
63
|
},
|
|
57
64
|
validateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {
|
|
@@ -29,7 +29,13 @@ export const railway = (options: RailwayOptions) => {
|
|
|
29
29
|
return {
|
|
30
30
|
id: "railway",
|
|
31
31
|
name: "Railway",
|
|
32
|
-
createAuthorizationURL({
|
|
32
|
+
createAuthorizationURL({
|
|
33
|
+
state,
|
|
34
|
+
scopes,
|
|
35
|
+
codeVerifier,
|
|
36
|
+
redirectURI,
|
|
37
|
+
additionalParams,
|
|
38
|
+
}) {
|
|
33
39
|
const _scopes = options.disableDefaultScope
|
|
34
40
|
? []
|
|
35
41
|
: ["openid", "email", "profile"];
|
|
@@ -43,6 +49,7 @@ export const railway = (options: RailwayOptions) => {
|
|
|
43
49
|
state,
|
|
44
50
|
codeVerifier,
|
|
45
51
|
redirectURI,
|
|
52
|
+
additionalParams,
|
|
46
53
|
});
|
|
47
54
|
},
|
|
48
55
|
validateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {
|
|
@@ -25,7 +25,7 @@ export const reddit = (options: RedditOptions) => {
|
|
|
25
25
|
return {
|
|
26
26
|
id: "reddit",
|
|
27
27
|
name: "Reddit",
|
|
28
|
-
createAuthorizationURL({ state, scopes, redirectURI }) {
|
|
28
|
+
createAuthorizationURL({ state, scopes, redirectURI, additionalParams }) {
|
|
29
29
|
const _scopes = options.disableDefaultScope ? [] : ["identity"];
|
|
30
30
|
if (options.scope) _scopes.push(...options.scope);
|
|
31
31
|
if (scopes) _scopes.push(...scopes);
|
|
@@ -37,6 +37,7 @@ export const reddit = (options: RedditOptions) => {
|
|
|
37
37
|
state,
|
|
38
38
|
redirectURI,
|
|
39
39
|
duration: options.duration,
|
|
40
|
+
additionalParams,
|
|
40
41
|
});
|
|
41
42
|
},
|
|
42
43
|
validateAuthorizationCode: async ({ code, redirectURI }) => {
|
|
@@ -104,15 +105,19 @@ export const reddit = (options: RedditOptions) => {
|
|
|
104
105
|
}
|
|
105
106
|
|
|
106
107
|
const userMap = await options.mapProfileToUser?.(profile);
|
|
107
|
-
|
|
108
|
+
// Reddit's identity scope does not return an email. Synthesize a stable,
|
|
109
|
+
// non-routable placeholder (RFC 2606 `.invalid`) keyed to the user's
|
|
110
|
+
// Reddit id rather than the routable `reddit.com`, which could collide
|
|
111
|
+
// with a real address. Left unverified; `mapProfileToUser` can override.
|
|
112
|
+
const email = userMap?.email || `${profile.id}@reddit.invalid`;
|
|
108
113
|
return {
|
|
109
114
|
user: {
|
|
110
115
|
id: profile.id,
|
|
111
116
|
name: profile.name,
|
|
112
|
-
email: profile.oauth_client_id,
|
|
113
|
-
emailVerified: profile.has_verified_email,
|
|
114
117
|
image: profile.icon_img?.split("?")[0]!,
|
|
115
118
|
...userMap,
|
|
119
|
+
email,
|
|
120
|
+
emailVerified: userMap?.emailVerified ?? false,
|
|
116
121
|
},
|
|
117
122
|
data: profile,
|
|
118
123
|
};
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { betterFetch } from "@better-fetch/fetch";
|
|
2
2
|
import type { OAuthProvider, ProviderOptions } from "../oauth2";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
createAuthorizationURL,
|
|
5
|
+
refreshAccessToken,
|
|
6
|
+
validateAuthorizationCode,
|
|
7
|
+
} from "../oauth2";
|
|
4
8
|
|
|
5
9
|
export interface RobloxProfile extends Record<string, any> {
|
|
6
10
|
/** the user's id */
|
|
@@ -37,19 +41,20 @@ export const roblox = (options: RobloxOptions) => {
|
|
|
37
41
|
return {
|
|
38
42
|
id: "roblox",
|
|
39
43
|
name: "Roblox",
|
|
40
|
-
createAuthorizationURL({ state, scopes, redirectURI }) {
|
|
44
|
+
createAuthorizationURL({ state, scopes, redirectURI, additionalParams }) {
|
|
41
45
|
const _scopes = options.disableDefaultScope ? [] : ["openid", "profile"];
|
|
42
46
|
if (options.scope) _scopes.push(...options.scope);
|
|
43
47
|
if (scopes) _scopes.push(...scopes);
|
|
44
|
-
return
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
48
|
+
return createAuthorizationURL({
|
|
49
|
+
id: "roblox",
|
|
50
|
+
options,
|
|
51
|
+
authorizationEndpoint: "https://apis.roblox.com/oauth/v1/authorize",
|
|
52
|
+
scopes: _scopes,
|
|
53
|
+
state,
|
|
54
|
+
redirectURI,
|
|
55
|
+
prompt: options.prompt || "select_account consent",
|
|
56
|
+
additionalParams,
|
|
57
|
+
});
|
|
53
58
|
},
|
|
54
59
|
validateAuthorizationCode: async ({ code, redirectURI }) => {
|
|
55
60
|
return validateAuthorizationCode({
|
|
@@ -64,7 +64,13 @@ export const salesforce = (options: SalesforceOptions) => {
|
|
|
64
64
|
id: "salesforce",
|
|
65
65
|
name: "Salesforce",
|
|
66
66
|
|
|
67
|
-
async createAuthorizationURL({
|
|
67
|
+
async createAuthorizationURL({
|
|
68
|
+
state,
|
|
69
|
+
scopes,
|
|
70
|
+
codeVerifier,
|
|
71
|
+
redirectURI,
|
|
72
|
+
additionalParams,
|
|
73
|
+
}) {
|
|
68
74
|
if (!options.clientId || !options.clientSecret) {
|
|
69
75
|
logger.error(
|
|
70
76
|
"Client Id and Client Secret are required for Salesforce. Make sure to provide them in the options.",
|
|
@@ -89,6 +95,7 @@ export const salesforce = (options: SalesforceOptions) => {
|
|
|
89
95
|
state,
|
|
90
96
|
codeVerifier,
|
|
91
97
|
redirectURI: options.redirectURI || redirectURI,
|
|
98
|
+
additionalParams,
|
|
92
99
|
});
|
|
93
100
|
},
|
|
94
101
|
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { betterFetch } from "@better-fetch/fetch";
|
|
2
2
|
import type { OAuthProvider, ProviderOptions } from "../oauth2";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
createAuthorizationURL,
|
|
5
|
+
refreshAccessToken,
|
|
6
|
+
validateAuthorizationCode,
|
|
7
|
+
} from "../oauth2";
|
|
4
8
|
|
|
5
9
|
export interface SlackProfile extends Record<string, any> {
|
|
6
10
|
ok: boolean;
|
|
@@ -42,19 +46,21 @@ export const slack = (options: SlackOptions) => {
|
|
|
42
46
|
return {
|
|
43
47
|
id: "slack",
|
|
44
48
|
name: "Slack",
|
|
45
|
-
createAuthorizationURL({ state, scopes, redirectURI }) {
|
|
49
|
+
createAuthorizationURL({ state, scopes, redirectURI, additionalParams }) {
|
|
46
50
|
const _scopes = options.disableDefaultScope
|
|
47
51
|
? []
|
|
48
52
|
: ["openid", "profile", "email"];
|
|
49
53
|
if (scopes) _scopes.push(...scopes);
|
|
50
54
|
if (options.scope) _scopes.push(...options.scope);
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
return createAuthorizationURL({
|
|
56
|
+
id: "slack",
|
|
57
|
+
options,
|
|
58
|
+
authorizationEndpoint: "https://slack.com/openid/connect/authorize",
|
|
59
|
+
scopes: _scopes,
|
|
60
|
+
state,
|
|
61
|
+
redirectURI,
|
|
62
|
+
additionalParams,
|
|
63
|
+
});
|
|
58
64
|
},
|
|
59
65
|
validateAuthorizationCode: async ({ code, redirectURI }) => {
|
|
60
66
|
return validateAuthorizationCode({
|
|
@@ -24,7 +24,13 @@ export const spotify = (options: SpotifyOptions) => {
|
|
|
24
24
|
return {
|
|
25
25
|
id: "spotify",
|
|
26
26
|
name: "Spotify",
|
|
27
|
-
createAuthorizationURL({
|
|
27
|
+
createAuthorizationURL({
|
|
28
|
+
state,
|
|
29
|
+
scopes,
|
|
30
|
+
codeVerifier,
|
|
31
|
+
redirectURI,
|
|
32
|
+
additionalParams,
|
|
33
|
+
}) {
|
|
28
34
|
const _scopes = options.disableDefaultScope ? [] : ["user-read-email"];
|
|
29
35
|
if (options.scope) _scopes.push(...options.scope);
|
|
30
36
|
if (scopes) _scopes.push(...scopes);
|
|
@@ -36,6 +42,7 @@ export const spotify = (options: SpotifyOptions) => {
|
|
|
36
42
|
state,
|
|
37
43
|
codeVerifier,
|
|
38
44
|
redirectURI,
|
|
45
|
+
additionalParams,
|
|
39
46
|
});
|
|
40
47
|
},
|
|
41
48
|
validateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { betterFetch } from "@better-fetch/fetch";
|
|
2
2
|
import type { OAuthProvider, ProviderOptions } from "../oauth2";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
RESERVED_AUTHORIZATION_PARAMS_SET,
|
|
5
|
+
refreshAccessToken,
|
|
6
|
+
validateAuthorizationCode,
|
|
7
|
+
} from "../oauth2";
|
|
4
8
|
|
|
5
9
|
/**
|
|
6
10
|
* [More info](https://developers.tiktok.com/doc/tiktok-api-v2-get-user-info/)
|
|
@@ -131,17 +135,26 @@ export const tiktok = (options: TiktokOptions) => {
|
|
|
131
135
|
return {
|
|
132
136
|
id: "tiktok",
|
|
133
137
|
name: "TikTok",
|
|
134
|
-
createAuthorizationURL({ state, scopes, redirectURI }) {
|
|
138
|
+
createAuthorizationURL({ state, scopes, redirectURI, additionalParams }) {
|
|
135
139
|
const _scopes = options.disableDefaultScope ? [] : ["user.info.profile"];
|
|
136
140
|
if (options.scope) _scopes.push(...options.scope);
|
|
137
141
|
if (scopes) _scopes.push(...scopes);
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
);
|
|
142
|
+
// TikTok uses `client_key` instead of the standard `client_id`, so the
|
|
143
|
+
// shared createAuthorizationURL helper cannot be used directly.
|
|
144
|
+
const url = new URL("https://www.tiktok.com/v2/auth/authorize");
|
|
145
|
+
url.searchParams.set("scope", _scopes.join(","));
|
|
146
|
+
url.searchParams.set("response_type", "code");
|
|
147
|
+
url.searchParams.set("client_key", options.clientKey);
|
|
148
|
+
url.searchParams.set("redirect_uri", options.redirectURI || redirectURI);
|
|
149
|
+
url.searchParams.set("state", state);
|
|
150
|
+
if (additionalParams) {
|
|
151
|
+
for (const [key, value] of Object.entries(additionalParams)) {
|
|
152
|
+
if (RESERVED_AUTHORIZATION_PARAMS_SET.has(key)) continue;
|
|
153
|
+
if (key === "client_key") continue;
|
|
154
|
+
url.searchParams.set(key, value);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return url;
|
|
145
158
|
},
|
|
146
159
|
|
|
147
160
|
validateAuthorizationCode: async ({ code, redirectURI }) => {
|
|
@@ -42,7 +42,7 @@ export const twitch = (options: TwitchOptions) => {
|
|
|
42
42
|
return {
|
|
43
43
|
id: "twitch",
|
|
44
44
|
name: "Twitch",
|
|
45
|
-
createAuthorizationURL({ state, scopes, redirectURI }) {
|
|
45
|
+
createAuthorizationURL({ state, scopes, redirectURI, additionalParams }) {
|
|
46
46
|
const _scopes = options.disableDefaultScope
|
|
47
47
|
? []
|
|
48
48
|
: ["user:read:email", "openid"];
|
|
@@ -61,6 +61,7 @@ export const twitch = (options: TwitchOptions) => {
|
|
|
61
61
|
"preferred_username",
|
|
62
62
|
"picture",
|
|
63
63
|
],
|
|
64
|
+
additionalParams,
|
|
64
65
|
});
|
|
65
66
|
},
|
|
66
67
|
validateAuthorizationCode: async ({ code, redirectURI }) => {
|
|
@@ -122,6 +122,7 @@ export const twitter = (options: TwitterOption) => {
|
|
|
122
122
|
state: data.state,
|
|
123
123
|
codeVerifier: data.codeVerifier,
|
|
124
124
|
redirectURI: data.redirectURI,
|
|
125
|
+
additionalParams: data.additionalParams,
|
|
125
126
|
});
|
|
126
127
|
},
|
|
127
128
|
validateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {
|
|
@@ -20,7 +20,13 @@ export const vercel = (options: VercelOptions) => {
|
|
|
20
20
|
return {
|
|
21
21
|
id: "vercel",
|
|
22
22
|
name: "Vercel",
|
|
23
|
-
createAuthorizationURL({
|
|
23
|
+
createAuthorizationURL({
|
|
24
|
+
state,
|
|
25
|
+
scopes,
|
|
26
|
+
codeVerifier,
|
|
27
|
+
redirectURI,
|
|
28
|
+
additionalParams,
|
|
29
|
+
}) {
|
|
24
30
|
if (!codeVerifier) {
|
|
25
31
|
throw new BetterAuthError("codeVerifier is required for Vercel");
|
|
26
32
|
}
|
|
@@ -40,6 +46,7 @@ export const vercel = (options: VercelOptions) => {
|
|
|
40
46
|
state,
|
|
41
47
|
codeVerifier,
|
|
42
48
|
redirectURI,
|
|
49
|
+
additionalParams,
|
|
43
50
|
});
|
|
44
51
|
},
|
|
45
52
|
validateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {
|
|
@@ -30,7 +30,13 @@ export const vk = (options: VkOption) => {
|
|
|
30
30
|
return {
|
|
31
31
|
id: "vk",
|
|
32
32
|
name: "VK",
|
|
33
|
-
async createAuthorizationURL({
|
|
33
|
+
async createAuthorizationURL({
|
|
34
|
+
state,
|
|
35
|
+
scopes,
|
|
36
|
+
codeVerifier,
|
|
37
|
+
redirectURI,
|
|
38
|
+
additionalParams,
|
|
39
|
+
}) {
|
|
34
40
|
const _scopes = options.disableDefaultScope ? [] : ["email", "phone"];
|
|
35
41
|
if (options.scope) _scopes.push(...options.scope);
|
|
36
42
|
if (scopes) _scopes.push(...scopes);
|
|
@@ -44,6 +50,7 @@ export const vk = (options: VkOption) => {
|
|
|
44
50
|
state,
|
|
45
51
|
redirectURI,
|
|
46
52
|
codeVerifier,
|
|
53
|
+
additionalParams,
|
|
47
54
|
});
|
|
48
55
|
},
|
|
49
56
|
validateAuthorizationCode: async ({
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { betterFetch } from "@better-fetch/fetch";
|
|
2
2
|
import type { OAuth2Tokens, OAuthProvider, ProviderOptions } from "../oauth2";
|
|
3
|
+
import { RESERVED_AUTHORIZATION_PARAMS_SET } from "../oauth2";
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* WeChat user profile information
|
|
@@ -58,7 +59,7 @@ export const wechat = (options: WeChatOptions) => {
|
|
|
58
59
|
return {
|
|
59
60
|
id: "wechat",
|
|
60
61
|
name: "WeChat",
|
|
61
|
-
createAuthorizationURL({ state, scopes, redirectURI }) {
|
|
62
|
+
createAuthorizationURL({ state, scopes, redirectURI, additionalParams }) {
|
|
62
63
|
const _scopes = options.disableDefaultScope ? [] : ["snsapi_login"];
|
|
63
64
|
options.scope && _scopes.push(...options.scope);
|
|
64
65
|
scopes && _scopes.push(...scopes);
|
|
@@ -72,6 +73,13 @@ export const wechat = (options: WeChatOptions) => {
|
|
|
72
73
|
url.searchParams.set("redirect_uri", options.redirectURI || redirectURI);
|
|
73
74
|
url.searchParams.set("state", state);
|
|
74
75
|
url.searchParams.set("lang", options.lang || "cn");
|
|
76
|
+
if (additionalParams) {
|
|
77
|
+
for (const [key, value] of Object.entries(additionalParams)) {
|
|
78
|
+
if (RESERVED_AUTHORIZATION_PARAMS_SET.has(key)) continue;
|
|
79
|
+
if (key === "appid") continue;
|
|
80
|
+
url.searchParams.set(key, value);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
75
83
|
url.hash = "wechat_redirect";
|
|
76
84
|
|
|
77
85
|
return url;
|
|
@@ -200,7 +208,14 @@ export const wechat = (options: WeChatOptions) => {
|
|
|
200
208
|
user: {
|
|
201
209
|
id: profile.unionid || profile.openid || openid,
|
|
202
210
|
name: profile.nickname,
|
|
203
|
-
|
|
211
|
+
// WeChat does not return an email, and the OAuth callback rejects a
|
|
212
|
+
// missing one, so the default sign-in would always fail. Synthesize a
|
|
213
|
+
// stable, non-routable placeholder (RFC 2606 `.invalid`) keyed to the
|
|
214
|
+
// user's WeChat id, left unverified. Applications that collect a real
|
|
215
|
+
// email override it via `mapProfileToUser`.
|
|
216
|
+
email:
|
|
217
|
+
profile.email ||
|
|
218
|
+
`${profile.unionid || profile.openid || openid}@wechat.invalid`,
|
|
204
219
|
image: profile.headimgurl,
|
|
205
220
|
emailVerified: false,
|
|
206
221
|
...userMap,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { betterFetch } from "@better-fetch/fetch";
|
|
2
2
|
import type { OAuthProvider, ProviderOptions } from "../oauth2";
|
|
3
3
|
import {
|
|
4
|
-
|
|
4
|
+
createAuthorizationURL,
|
|
5
5
|
refreshAccessToken,
|
|
6
6
|
validateAuthorizationCode,
|
|
7
7
|
} from "../oauth2";
|
|
@@ -152,25 +152,21 @@ export const zoom = (userOptions: ZoomOptions) => {
|
|
|
152
152
|
return {
|
|
153
153
|
id: "zoom",
|
|
154
154
|
name: "Zoom",
|
|
155
|
-
createAuthorizationURL: async ({
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
155
|
+
createAuthorizationURL: async ({
|
|
156
|
+
state,
|
|
157
|
+
redirectURI,
|
|
158
|
+
codeVerifier,
|
|
159
|
+
additionalParams,
|
|
160
|
+
}) =>
|
|
161
|
+
createAuthorizationURL({
|
|
162
|
+
id: "zoom",
|
|
163
|
+
options,
|
|
164
|
+
authorizationEndpoint: "https://zoom.us/oauth/authorize",
|
|
160
165
|
state,
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
params.set("code_challenge_method", "S256");
|
|
166
|
-
params.set("code_challenge", codeChallenge);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
const url = new URL("https://zoom.us/oauth/authorize");
|
|
170
|
-
url.search = params.toString();
|
|
171
|
-
|
|
172
|
-
return url;
|
|
173
|
-
},
|
|
166
|
+
redirectURI,
|
|
167
|
+
codeVerifier: options.pkce ? codeVerifier : undefined,
|
|
168
|
+
additionalParams,
|
|
169
|
+
}),
|
|
174
170
|
validateAuthorizationCode: async ({ code, redirectURI, codeVerifier }) => {
|
|
175
171
|
return validateAuthorizationCode({
|
|
176
172
|
code,
|