@depup/better-auth__core 1.6.23-depup.2
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 +20 -0
- package/README.md +32 -0
- package/changes.json +14 -0
- package/dist/api/index.d.mts +281 -0
- package/dist/api/index.mjs +92 -0
- package/dist/async_hooks/index.d.mts +6 -0
- package/dist/async_hooks/index.mjs +20 -0
- package/dist/async_hooks/pure.index.d.mts +6 -0
- package/dist/async_hooks/pure.index.mjs +33 -0
- package/dist/context/endpoint-context.d.mts +18 -0
- package/dist/context/endpoint-context.mjs +29 -0
- package/dist/context/global.d.mts +6 -0
- package/dist/context/global.mjs +36 -0
- package/dist/context/index.d.mts +5 -0
- package/dist/context/index.mjs +5 -0
- package/dist/context/request-state.d.mts +27 -0
- package/dist/context/request-state.mjs +47 -0
- package/dist/context/transaction.d.mts +27 -0
- package/dist/context/transaction.mjs +96 -0
- package/dist/db/adapter/factory.d.mts +17 -0
- package/dist/db/adapter/factory.mjs +905 -0
- package/dist/db/adapter/get-default-field-name.d.mts +18 -0
- package/dist/db/adapter/get-default-field-name.mjs +36 -0
- package/dist/db/adapter/get-default-model-name.d.mts +12 -0
- package/dist/db/adapter/get-default-model-name.mjs +30 -0
- package/dist/db/adapter/get-field-attributes.d.mts +26 -0
- package/dist/db/adapter/get-field-attributes.mjs +37 -0
- package/dist/db/adapter/get-field-name.d.mts +18 -0
- package/dist/db/adapter/get-field-name.mjs +31 -0
- package/dist/db/adapter/get-id-field.d.mts +36 -0
- package/dist/db/adapter/get-id-field.mjs +64 -0
- package/dist/db/adapter/get-model-name.d.mts +12 -0
- package/dist/db/adapter/get-model-name.mjs +21 -0
- package/dist/db/adapter/index.d.mts +615 -0
- package/dist/db/adapter/index.mjs +24 -0
- package/dist/db/adapter/types.d.mts +105 -0
- package/dist/db/adapter/utils.d.mts +7 -0
- package/dist/db/adapter/utils.mjs +37 -0
- package/dist/db/get-tables.d.mts +6 -0
- package/dist/db/get-tables.mjs +266 -0
- package/dist/db/index.d.mts +10 -0
- package/dist/db/index.mjs +8 -0
- package/dist/db/plugin.d.mts +12 -0
- package/dist/db/schema/account.d.mts +28 -0
- package/dist/db/schema/account.mjs +17 -0
- package/dist/db/schema/rate-limit.d.mts +18 -0
- package/dist/db/schema/rate-limit.mjs +9 -0
- package/dist/db/schema/session.d.mts +23 -0
- package/dist/db/schema/session.mjs +12 -0
- package/dist/db/schema/shared.d.mts +10 -0
- package/dist/db/schema/shared.mjs +9 -0
- package/dist/db/schema/user.d.mts +22 -0
- package/dist/db/schema/user.mjs +11 -0
- package/dist/db/schema/verification.d.mts +21 -0
- package/dist/db/schema/verification.mjs +10 -0
- package/dist/db/type.d.mts +194 -0
- package/dist/env/color-depth.d.mts +4 -0
- package/dist/env/color-depth.mjs +86 -0
- package/dist/env/env-impl.d.mts +32 -0
- package/dist/env/env-impl.mjs +81 -0
- package/dist/env/index.d.mts +4 -0
- package/dist/env/index.mjs +4 -0
- package/dist/env/logger.d.mts +48 -0
- package/dist/env/logger.mjs +79 -0
- package/dist/error/codes.d.mts +69 -0
- package/dist/error/codes.mjs +55 -0
- package/dist/error/index.d.mts +26 -0
- package/dist/error/index.mjs +27 -0
- package/dist/index.d.mts +9 -0
- package/dist/index.mjs +1 -0
- package/dist/instrumentation/api.mjs +12 -0
- package/dist/instrumentation/attributes.d.mts +11 -0
- package/dist/instrumentation/attributes.mjs +10 -0
- package/dist/instrumentation/index.d.mts +3 -0
- package/dist/instrumentation/index.mjs +3 -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.d.mts +13 -0
- package/dist/instrumentation/tracer.mjs +53 -0
- package/dist/oauth2/client-credentials-token.d.mts +56 -0
- package/dist/oauth2/client-credentials-token.mjs +64 -0
- package/dist/oauth2/create-authorization-url.d.mts +44 -0
- package/dist/oauth2/create-authorization-url.mjs +41 -0
- package/dist/oauth2/index.d.mts +8 -0
- package/dist/oauth2/index.mjs +7 -0
- package/dist/oauth2/oauth-provider.d.mts +192 -0
- package/dist/oauth2/refresh-access-token.d.mts +54 -0
- package/dist/oauth2/refresh-access-token.mjs +73 -0
- package/dist/oauth2/reject-redirects.mjs +60 -0
- package/dist/oauth2/utils.d.mts +24 -0
- package/dist/oauth2/utils.mjs +48 -0
- package/dist/oauth2/validate-authorization-code.d.mts +85 -0
- package/dist/oauth2/validate-authorization-code.mjs +86 -0
- package/dist/oauth2/verify.d.mts +65 -0
- package/dist/oauth2/verify.mjs +202 -0
- package/dist/social-providers/apple.d.mts +133 -0
- package/dist/social-providers/apple.mjs +117 -0
- package/dist/social-providers/atlassian.d.mts +70 -0
- package/dist/social-providers/atlassian.mjs +80 -0
- package/dist/social-providers/cognito.d.mts +85 -0
- package/dist/social-providers/cognito.mjs +162 -0
- package/dist/social-providers/discord.d.mts +124 -0
- package/dist/social-providers/discord.mjs +62 -0
- package/dist/social-providers/dropbox.d.mts +69 -0
- package/dist/social-providers/dropbox.mjs +72 -0
- package/dist/social-providers/facebook.d.mts +79 -0
- package/dist/social-providers/facebook.mjs +157 -0
- package/dist/social-providers/figma.d.mts +61 -0
- package/dist/social-providers/figma.mjs +83 -0
- package/dist/social-providers/github.d.mts +102 -0
- package/dist/social-providers/github.mjs +92 -0
- package/dist/social-providers/gitlab.d.mts +123 -0
- package/dist/social-providers/gitlab.mjs +79 -0
- package/dist/social-providers/google.d.mts +123 -0
- package/dist/social-providers/google.mjs +137 -0
- package/dist/social-providers/huggingface.d.mts +83 -0
- package/dist/social-providers/huggingface.mjs +73 -0
- package/dist/social-providers/index.d.mts +1834 -0
- package/dist/social-providers/index.mjs +78 -0
- package/dist/social-providers/kakao.d.mts +161 -0
- package/dist/social-providers/kakao.mjs +70 -0
- package/dist/social-providers/kick.d.mts +73 -0
- package/dist/social-providers/kick.mjs +68 -0
- package/dist/social-providers/line.d.mts +105 -0
- package/dist/social-providers/line.mjs +110 -0
- package/dist/social-providers/linear.d.mts +68 -0
- package/dist/social-providers/linear.mjs +85 -0
- package/dist/social-providers/linkedin.d.mts +67 -0
- package/dist/social-providers/linkedin.mjs +73 -0
- package/dist/social-providers/microsoft-entra-id.d.mts +174 -0
- package/dist/social-providers/microsoft-entra-id.mjs +152 -0
- package/dist/social-providers/naver.d.mts +92 -0
- package/dist/social-providers/naver.mjs +65 -0
- package/dist/social-providers/notion.d.mts +64 -0
- package/dist/social-providers/notion.mjs +72 -0
- package/dist/social-providers/paybin.d.mts +71 -0
- package/dist/social-providers/paybin.mjs +81 -0
- package/dist/social-providers/paypal.d.mts +131 -0
- package/dist/social-providers/paypal.mjs +188 -0
- package/dist/social-providers/polar.d.mts +74 -0
- package/dist/social-providers/polar.mjs +71 -0
- package/dist/social-providers/railway.d.mts +65 -0
- package/dist/social-providers/railway.mjs +74 -0
- package/dist/social-providers/reddit.d.mts +62 -0
- package/dist/social-providers/reddit.mjs +81 -0
- package/dist/social-providers/roblox.d.mts +70 -0
- package/dist/social-providers/roblox.mjs +57 -0
- package/dist/social-providers/salesforce.d.mts +79 -0
- package/dist/social-providers/salesforce.mjs +87 -0
- package/dist/social-providers/slack.d.mts +83 -0
- package/dist/social-providers/slack.mjs +66 -0
- package/dist/social-providers/spotify.d.mts +63 -0
- package/dist/social-providers/spotify.mjs +69 -0
- package/dist/social-providers/tiktok.d.mts +168 -0
- package/dist/social-providers/tiktok.mjs +60 -0
- package/dist/social-providers/twitch.d.mts +79 -0
- package/dist/social-providers/twitch.mjs +75 -0
- package/dist/social-providers/twitter.d.mts +126 -0
- package/dist/social-providers/twitter.mjs +85 -0
- package/dist/social-providers/vercel.d.mts +62 -0
- package/dist/social-providers/vercel.mjs +58 -0
- package/dist/social-providers/vk.d.mts +70 -0
- package/dist/social-providers/vk.mjs +81 -0
- package/dist/social-providers/wechat.d.mts +113 -0
- package/dist/social-providers/wechat.mjs +81 -0
- package/dist/social-providers/zoom.d.mts +163 -0
- package/dist/social-providers/zoom.mjs +69 -0
- package/dist/types/context.d.mts +319 -0
- package/dist/types/cookie.d.mts +15 -0
- package/dist/types/helper.d.mts +10 -0
- package/dist/types/index.d.mts +9 -0
- package/dist/types/init-options.d.mts +1430 -0
- package/dist/types/plugin-client.d.mts +123 -0
- package/dist/types/plugin.d.mts +124 -0
- package/dist/types/secret.d.mts +11 -0
- package/dist/utils/async.d.mts +22 -0
- package/dist/utils/async.mjs +32 -0
- package/dist/utils/db.d.mts +9 -0
- package/dist/utils/db.mjs +15 -0
- package/dist/utils/deprecate.d.mts +9 -0
- package/dist/utils/deprecate.mjs +16 -0
- package/dist/utils/error-codes.d.mts +13 -0
- package/dist/utils/error-codes.mjs +10 -0
- package/dist/utils/fetch-metadata.d.mts +4 -0
- package/dist/utils/fetch-metadata.mjs +6 -0
- package/dist/utils/host.d.mts +147 -0
- package/dist/utils/host.mjs +295 -0
- package/dist/utils/id.d.mts +4 -0
- package/dist/utils/id.mjs +7 -0
- package/dist/utils/ip.d.mts +77 -0
- package/dist/utils/ip.mjs +230 -0
- package/dist/utils/is-api-error.d.mts +6 -0
- package/dist/utils/is-api-error.mjs +8 -0
- package/dist/utils/json.d.mts +4 -0
- package/dist/utils/json.mjs +41 -0
- package/dist/utils/redirect-uri.d.mts +20 -0
- package/dist/utils/redirect-uri.mjs +48 -0
- package/dist/utils/string.d.mts +8 -0
- package/dist/utils/string.mjs +25 -0
- package/dist/utils/url.d.mts +37 -0
- package/dist/utils/url.mjs +61 -0
- package/package.json +216 -0
- package/src/api/index.ts +185 -0
- package/src/async_hooks/index.ts +40 -0
- package/src/async_hooks/pure.index.ts +46 -0
- package/src/context/endpoint-context.ts +50 -0
- package/src/context/global.ts +57 -0
- package/src/context/index.ts +23 -0
- package/src/context/request-state.ts +91 -0
- package/src/context/transaction.ts +169 -0
- package/src/db/adapter/factory.ts +1740 -0
- package/src/db/adapter/get-default-field-name.ts +59 -0
- package/src/db/adapter/get-default-model-name.ts +51 -0
- package/src/db/adapter/get-field-attributes.ts +62 -0
- package/src/db/adapter/get-field-name.ts +43 -0
- package/src/db/adapter/get-id-field.ts +150 -0
- package/src/db/adapter/get-model-name.ts +36 -0
- package/src/db/adapter/index.ts +656 -0
- package/src/db/adapter/types.ts +134 -0
- package/src/db/adapter/utils.ts +61 -0
- package/src/db/get-tables.ts +304 -0
- package/src/db/index.ts +43 -0
- package/src/db/plugin.ts +11 -0
- package/src/db/schema/account.ts +47 -0
- package/src/db/schema/rate-limit.ts +36 -0
- package/src/db/schema/session.ts +29 -0
- package/src/db/schema/shared.ts +7 -0
- package/src/db/schema/user.ts +31 -0
- package/src/db/schema/verification.ts +28 -0
- package/src/db/type.ts +360 -0
- package/src/env/color-depth.ts +172 -0
- package/src/env/env-impl.ts +123 -0
- package/src/env/index.ts +23 -0
- package/src/env/logger.ts +145 -0
- package/src/error/codes.ts +72 -0
- package/src/error/index.ts +44 -0
- package/src/index.ts +1 -0
- package/src/instrumentation/api.ts +17 -0
- package/src/instrumentation/attributes.ts +22 -0
- package/src/instrumentation/index.ts +2 -0
- package/src/instrumentation/noop.ts +74 -0
- package/src/instrumentation/pure.index.ts +31 -0
- package/src/instrumentation/tracer.ts +95 -0
- package/src/oauth2/client-credentials-token.ts +126 -0
- package/src/oauth2/create-authorization-url.ts +89 -0
- package/src/oauth2/index.ts +34 -0
- package/src/oauth2/oauth-provider.ts +222 -0
- package/src/oauth2/refresh-access-token.ts +157 -0
- package/src/oauth2/reject-redirects.ts +70 -0
- package/src/oauth2/utils.ts +70 -0
- package/src/oauth2/validate-authorization-code.ts +190 -0
- package/src/oauth2/verify.ts +408 -0
- package/src/social-providers/apple.ts +249 -0
- package/src/social-providers/atlassian.ts +133 -0
- package/src/social-providers/cognito.ts +281 -0
- package/src/social-providers/discord.ts +170 -0
- package/src/social-providers/dropbox.ts +112 -0
- package/src/social-providers/facebook.ts +288 -0
- package/src/social-providers/figma.ts +118 -0
- package/src/social-providers/github.ts +184 -0
- package/src/social-providers/gitlab.ts +155 -0
- package/src/social-providers/google.ts +263 -0
- package/src/social-providers/huggingface.ts +119 -0
- package/src/social-providers/index.ts +132 -0
- package/src/social-providers/kakao.ts +179 -0
- package/src/social-providers/kick.ts +109 -0
- package/src/social-providers/line.ts +169 -0
- package/src/social-providers/linear.ts +121 -0
- package/src/social-providers/linkedin.ts +110 -0
- package/src/social-providers/microsoft-entra-id.ts +391 -0
- package/src/social-providers/naver.ts +113 -0
- package/src/social-providers/notion.ts +108 -0
- package/src/social-providers/paybin.ts +118 -0
- package/src/social-providers/paypal.ts +371 -0
- package/src/social-providers/polar.ts +111 -0
- package/src/social-providers/railway.ts +100 -0
- package/src/social-providers/reddit.ts +126 -0
- package/src/social-providers/roblox.ts +112 -0
- package/src/social-providers/salesforce.ts +159 -0
- package/src/social-providers/slack.ts +112 -0
- package/src/social-providers/spotify.ts +94 -0
- package/src/social-providers/tiktok.ts +211 -0
- package/src/social-providers/twitch.ts +112 -0
- package/src/social-providers/twitter.ts +199 -0
- package/src/social-providers/vercel.ts +87 -0
- package/src/social-providers/vk.ts +125 -0
- package/src/social-providers/wechat.ts +220 -0
- package/src/social-providers/zoom.ts +230 -0
- package/src/types/context.ts +460 -0
- package/src/types/cookie.ts +10 -0
- package/src/types/helper.ts +27 -0
- package/src/types/index.ts +40 -0
- package/src/types/init-options.ts +1679 -0
- package/src/types/plugin-client.ts +143 -0
- package/src/types/plugin.ts +163 -0
- package/src/types/secret.ts +8 -0
- package/src/utils/async.ts +53 -0
- package/src/utils/db.ts +20 -0
- package/src/utils/deprecate.ts +21 -0
- package/src/utils/error-codes.ts +68 -0
- package/src/utils/fetch-metadata.ts +3 -0
- package/src/utils/host.ts +416 -0
- package/src/utils/id.ts +5 -0
- package/src/utils/ip.ts +395 -0
- package/src/utils/is-api-error.ts +10 -0
- package/src/utils/json.ts +56 -0
- package/src/utils/redirect-uri.ts +54 -0
- package/src/utils/string.ts +40 -0
- package/src/utils/url.ts +77 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { betterFetch } from "@better-fetch/fetch";
|
|
2
|
+
import type { OAuthProvider, ProviderOptions } from "../oauth2";
|
|
3
|
+
import {
|
|
4
|
+
createAuthorizationURL,
|
|
5
|
+
refreshAccessToken,
|
|
6
|
+
validateAuthorizationCode,
|
|
7
|
+
} from "../oauth2";
|
|
8
|
+
|
|
9
|
+
export interface VkProfile {
|
|
10
|
+
user: {
|
|
11
|
+
user_id: string;
|
|
12
|
+
first_name: string;
|
|
13
|
+
last_name: string;
|
|
14
|
+
email?: string | undefined;
|
|
15
|
+
phone?: number | undefined;
|
|
16
|
+
avatar?: string | undefined;
|
|
17
|
+
sex?: number | undefined;
|
|
18
|
+
verified?: boolean | undefined;
|
|
19
|
+
birthday: string;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface VkOption extends ProviderOptions {
|
|
24
|
+
clientId: string;
|
|
25
|
+
scheme?: ("light" | "dark") | undefined;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const vk = (options: VkOption) => {
|
|
29
|
+
const tokenEndpoint = "https://id.vk.com/oauth2/auth";
|
|
30
|
+
return {
|
|
31
|
+
id: "vk",
|
|
32
|
+
name: "VK",
|
|
33
|
+
async createAuthorizationURL({ state, scopes, codeVerifier, redirectURI }) {
|
|
34
|
+
const _scopes = options.disableDefaultScope ? [] : ["email", "phone"];
|
|
35
|
+
if (options.scope) _scopes.push(...options.scope);
|
|
36
|
+
if (scopes) _scopes.push(...scopes);
|
|
37
|
+
const authorizationEndpoint = "https://id.vk.com/authorize";
|
|
38
|
+
|
|
39
|
+
return createAuthorizationURL({
|
|
40
|
+
id: "vk",
|
|
41
|
+
options,
|
|
42
|
+
authorizationEndpoint,
|
|
43
|
+
scopes: _scopes,
|
|
44
|
+
state,
|
|
45
|
+
redirectURI,
|
|
46
|
+
codeVerifier,
|
|
47
|
+
});
|
|
48
|
+
},
|
|
49
|
+
validateAuthorizationCode: async ({
|
|
50
|
+
code,
|
|
51
|
+
codeVerifier,
|
|
52
|
+
redirectURI,
|
|
53
|
+
deviceId,
|
|
54
|
+
}) => {
|
|
55
|
+
return validateAuthorizationCode({
|
|
56
|
+
code,
|
|
57
|
+
codeVerifier,
|
|
58
|
+
redirectURI: options.redirectURI || redirectURI,
|
|
59
|
+
options,
|
|
60
|
+
deviceId,
|
|
61
|
+
tokenEndpoint,
|
|
62
|
+
});
|
|
63
|
+
},
|
|
64
|
+
refreshAccessToken: options.refreshAccessToken
|
|
65
|
+
? options.refreshAccessToken
|
|
66
|
+
: async (refreshToken) => {
|
|
67
|
+
return refreshAccessToken({
|
|
68
|
+
refreshToken,
|
|
69
|
+
options: {
|
|
70
|
+
clientId: options.clientId,
|
|
71
|
+
clientKey: options.clientKey,
|
|
72
|
+
clientSecret: options.clientSecret,
|
|
73
|
+
},
|
|
74
|
+
tokenEndpoint,
|
|
75
|
+
});
|
|
76
|
+
},
|
|
77
|
+
async getUserInfo(data) {
|
|
78
|
+
if (options.getUserInfo) {
|
|
79
|
+
return options.getUserInfo(data);
|
|
80
|
+
}
|
|
81
|
+
if (!data.accessToken) {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
const formBody = new URLSearchParams({
|
|
85
|
+
access_token: data.accessToken,
|
|
86
|
+
client_id: options.clientId,
|
|
87
|
+
}).toString();
|
|
88
|
+
const { data: profile, error } = await betterFetch<VkProfile>(
|
|
89
|
+
"https://id.vk.com/oauth2/user_info",
|
|
90
|
+
{
|
|
91
|
+
method: "POST",
|
|
92
|
+
headers: {
|
|
93
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
94
|
+
},
|
|
95
|
+
body: formBody,
|
|
96
|
+
},
|
|
97
|
+
);
|
|
98
|
+
if (error) {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const userMap = await options.mapProfileToUser?.(profile);
|
|
103
|
+
if (!profile.user.email && !userMap?.email) {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
user: {
|
|
109
|
+
id: profile.user.user_id,
|
|
110
|
+
first_name: profile.user.first_name,
|
|
111
|
+
last_name: profile.user.last_name,
|
|
112
|
+
email: profile.user.email,
|
|
113
|
+
image: profile.user.avatar,
|
|
114
|
+
emailVerified: false,
|
|
115
|
+
birthday: profile.user.birthday,
|
|
116
|
+
sex: profile.user.sex,
|
|
117
|
+
name: `${profile.user.first_name} ${profile.user.last_name}`,
|
|
118
|
+
...userMap,
|
|
119
|
+
},
|
|
120
|
+
data: profile,
|
|
121
|
+
};
|
|
122
|
+
},
|
|
123
|
+
options,
|
|
124
|
+
} satisfies OAuthProvider<VkProfile>;
|
|
125
|
+
};
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { betterFetch } from "@better-fetch/fetch";
|
|
2
|
+
import type { OAuth2Tokens, OAuthProvider, ProviderOptions } from "../oauth2";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* WeChat user profile information
|
|
6
|
+
* @see https://developers.weixin.qq.com/doc/oplatform/en/Website_App/WeChat_Login/Wechat_Login.html
|
|
7
|
+
*/
|
|
8
|
+
export interface WeChatProfile extends Record<string, any> {
|
|
9
|
+
/**
|
|
10
|
+
* User's unique OpenID
|
|
11
|
+
*/
|
|
12
|
+
openid: string;
|
|
13
|
+
/**
|
|
14
|
+
* User's nickname
|
|
15
|
+
*/
|
|
16
|
+
nickname: string;
|
|
17
|
+
/**
|
|
18
|
+
* User's avatar image URL
|
|
19
|
+
*/
|
|
20
|
+
headimgurl: string;
|
|
21
|
+
/**
|
|
22
|
+
* User's privileges
|
|
23
|
+
*/
|
|
24
|
+
privilege: string[];
|
|
25
|
+
/**
|
|
26
|
+
* User's UnionID (unique across the developer's various applications)
|
|
27
|
+
*/
|
|
28
|
+
unionid?: string;
|
|
29
|
+
/** @note Email is currently unsupported by WeChat */
|
|
30
|
+
email?: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface WeChatOptions extends ProviderOptions<WeChatProfile> {
|
|
34
|
+
/**
|
|
35
|
+
* WeChat App ID
|
|
36
|
+
*/
|
|
37
|
+
clientId: string;
|
|
38
|
+
/**
|
|
39
|
+
* WeChat App Secret
|
|
40
|
+
*/
|
|
41
|
+
clientSecret: string;
|
|
42
|
+
/**
|
|
43
|
+
* Platform type for WeChat login
|
|
44
|
+
* - Currently only supports "WebsiteApp" for WeChat Website Application (网站应用)
|
|
45
|
+
* @default "WebsiteApp"
|
|
46
|
+
*/
|
|
47
|
+
platformType?: "WebsiteApp";
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* UI language for the WeChat login page
|
|
51
|
+
* cn for Simplified Chinese, en for English
|
|
52
|
+
* @default "cn" if left undefined
|
|
53
|
+
*/
|
|
54
|
+
lang?: "cn" | "en";
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export const wechat = (options: WeChatOptions) => {
|
|
58
|
+
return {
|
|
59
|
+
id: "wechat",
|
|
60
|
+
name: "WeChat",
|
|
61
|
+
createAuthorizationURL({ state, scopes, redirectURI }) {
|
|
62
|
+
const _scopes = options.disableDefaultScope ? [] : ["snsapi_login"];
|
|
63
|
+
options.scope && _scopes.push(...options.scope);
|
|
64
|
+
scopes && _scopes.push(...scopes);
|
|
65
|
+
|
|
66
|
+
// WeChat uses non-standard OAuth2 parameters (appid instead of client_id)
|
|
67
|
+
// and requires a fragment (#wechat_redirect), so we construct the URL manually.
|
|
68
|
+
const url = new URL("https://open.weixin.qq.com/connect/qrconnect");
|
|
69
|
+
url.searchParams.set("scope", _scopes.join(","));
|
|
70
|
+
url.searchParams.set("response_type", "code");
|
|
71
|
+
url.searchParams.set("appid", options.clientId);
|
|
72
|
+
url.searchParams.set("redirect_uri", options.redirectURI || redirectURI);
|
|
73
|
+
url.searchParams.set("state", state);
|
|
74
|
+
url.searchParams.set("lang", options.lang || "cn");
|
|
75
|
+
url.hash = "wechat_redirect";
|
|
76
|
+
|
|
77
|
+
return url;
|
|
78
|
+
},
|
|
79
|
+
|
|
80
|
+
// WeChat uses non-standard token exchange (appid/secret instead of
|
|
81
|
+
// client_id/client_secret, GET instead of POST), so shared helpers
|
|
82
|
+
// like validateAuthorizationCode/getOAuth2Tokens cannot be used directly.
|
|
83
|
+
validateAuthorizationCode: async ({ code }) => {
|
|
84
|
+
const params = new URLSearchParams({
|
|
85
|
+
appid: options.clientId,
|
|
86
|
+
secret: options.clientSecret,
|
|
87
|
+
code: code,
|
|
88
|
+
grant_type: "authorization_code",
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
const { data: tokenData, error } = await betterFetch<{
|
|
92
|
+
access_token: string;
|
|
93
|
+
expires_in: number;
|
|
94
|
+
refresh_token: string;
|
|
95
|
+
openid: string;
|
|
96
|
+
scope: string;
|
|
97
|
+
unionid?: string;
|
|
98
|
+
errcode?: number;
|
|
99
|
+
errmsg?: string;
|
|
100
|
+
}>(
|
|
101
|
+
"https://api.weixin.qq.com/sns/oauth2/access_token?" +
|
|
102
|
+
params.toString(),
|
|
103
|
+
{
|
|
104
|
+
method: "GET",
|
|
105
|
+
},
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
if (error || !tokenData || tokenData.errcode) {
|
|
109
|
+
throw new Error(
|
|
110
|
+
`Failed to validate authorization code: ${tokenData?.errmsg || error?.message || "Unknown error"}`,
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return {
|
|
115
|
+
tokenType: "Bearer" as const,
|
|
116
|
+
accessToken: tokenData.access_token,
|
|
117
|
+
refreshToken: tokenData.refresh_token,
|
|
118
|
+
accessTokenExpiresAt: new Date(
|
|
119
|
+
Date.now() + tokenData.expires_in * 1000,
|
|
120
|
+
),
|
|
121
|
+
scopes: tokenData.scope.split(","),
|
|
122
|
+
// WeChat requires openid for the userinfo endpoint, which is
|
|
123
|
+
// returned alongside the access token.
|
|
124
|
+
openid: tokenData.openid,
|
|
125
|
+
unionid: tokenData.unionid,
|
|
126
|
+
};
|
|
127
|
+
},
|
|
128
|
+
|
|
129
|
+
refreshAccessToken: options.refreshAccessToken
|
|
130
|
+
? options.refreshAccessToken
|
|
131
|
+
: async (refreshToken) => {
|
|
132
|
+
const params = new URLSearchParams({
|
|
133
|
+
appid: options.clientId,
|
|
134
|
+
grant_type: "refresh_token",
|
|
135
|
+
refresh_token: refreshToken,
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
const { data: tokenData, error } = await betterFetch<{
|
|
139
|
+
access_token: string;
|
|
140
|
+
expires_in: number;
|
|
141
|
+
refresh_token: string;
|
|
142
|
+
openid: string;
|
|
143
|
+
scope: string;
|
|
144
|
+
errcode?: number;
|
|
145
|
+
errmsg?: string;
|
|
146
|
+
}>(
|
|
147
|
+
"https://api.weixin.qq.com/sns/oauth2/refresh_token?" +
|
|
148
|
+
params.toString(),
|
|
149
|
+
{
|
|
150
|
+
method: "GET",
|
|
151
|
+
},
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
if (error || !tokenData || tokenData.errcode) {
|
|
155
|
+
throw new Error(
|
|
156
|
+
`Failed to refresh access token: ${tokenData?.errmsg || error?.message || "Unknown error"}`,
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return {
|
|
161
|
+
tokenType: "Bearer" as const,
|
|
162
|
+
accessToken: tokenData.access_token,
|
|
163
|
+
refreshToken: tokenData.refresh_token,
|
|
164
|
+
accessTokenExpiresAt: new Date(
|
|
165
|
+
Date.now() + tokenData.expires_in * 1000,
|
|
166
|
+
),
|
|
167
|
+
scopes: tokenData.scope.split(","),
|
|
168
|
+
};
|
|
169
|
+
},
|
|
170
|
+
|
|
171
|
+
async getUserInfo(token) {
|
|
172
|
+
if (options.getUserInfo) {
|
|
173
|
+
return options.getUserInfo(token);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const openid = (token as OAuth2Tokens & { openid?: string }).openid;
|
|
177
|
+
|
|
178
|
+
if (!openid) {
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const params = new URLSearchParams({
|
|
183
|
+
access_token: token.accessToken || "",
|
|
184
|
+
openid: openid,
|
|
185
|
+
lang: "zh_CN",
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
const { data: profile, error } = await betterFetch<
|
|
189
|
+
WeChatProfile & { errcode?: number; errmsg?: string }
|
|
190
|
+
>("https://api.weixin.qq.com/sns/userinfo?" + params.toString(), {
|
|
191
|
+
method: "GET",
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
if (error || !profile || profile.errcode) {
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const userMap = await options.mapProfileToUser?.(profile);
|
|
199
|
+
return {
|
|
200
|
+
user: {
|
|
201
|
+
id: profile.unionid || profile.openid || openid,
|
|
202
|
+
name: profile.nickname,
|
|
203
|
+
// WeChat does not return an email, and the OAuth callback rejects a
|
|
204
|
+
// missing one, so the default sign-in would always fail. Synthesize a
|
|
205
|
+
// stable, non-routable placeholder (RFC 2606 `.invalid`) keyed to the
|
|
206
|
+
// user's WeChat id, left unverified. Applications that collect a real
|
|
207
|
+
// email override it via `mapProfileToUser`.
|
|
208
|
+
email:
|
|
209
|
+
profile.email ||
|
|
210
|
+
`${profile.unionid || profile.openid || openid}@wechat.invalid`,
|
|
211
|
+
image: profile.headimgurl,
|
|
212
|
+
emailVerified: false,
|
|
213
|
+
...userMap,
|
|
214
|
+
},
|
|
215
|
+
data: profile,
|
|
216
|
+
};
|
|
217
|
+
},
|
|
218
|
+
options,
|
|
219
|
+
} satisfies OAuthProvider<WeChatProfile, WeChatOptions>;
|
|
220
|
+
};
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import { betterFetch } from "@better-fetch/fetch";
|
|
2
|
+
import type { OAuthProvider, ProviderOptions } from "../oauth2";
|
|
3
|
+
import {
|
|
4
|
+
generateCodeChallenge,
|
|
5
|
+
refreshAccessToken,
|
|
6
|
+
validateAuthorizationCode,
|
|
7
|
+
} from "../oauth2";
|
|
8
|
+
|
|
9
|
+
export type LoginType =
|
|
10
|
+
| 0 /** Facebook OAuth */
|
|
11
|
+
| 1 /** Google OAuth */
|
|
12
|
+
| 24 /** Apple OAuth */
|
|
13
|
+
| 27 /** Microsoft OAuth */
|
|
14
|
+
| 97 /** Mobile device */
|
|
15
|
+
| 98 /** RingCentral OAuth */
|
|
16
|
+
| 99 /** API user */
|
|
17
|
+
| 100 /** Zoom Work email */
|
|
18
|
+
| 101; /** Single Sign-On (SSO) */
|
|
19
|
+
|
|
20
|
+
export type AccountStatus = "pending" | "active" | "inactive";
|
|
21
|
+
|
|
22
|
+
export type PronounOption =
|
|
23
|
+
| 1 /** Ask the user every time */
|
|
24
|
+
| 2 /** Always display */
|
|
25
|
+
| 3; /** Do not display */
|
|
26
|
+
|
|
27
|
+
export interface PhoneNumber {
|
|
28
|
+
/** The country code of the phone number (Example: "+1") */
|
|
29
|
+
code: string;
|
|
30
|
+
|
|
31
|
+
/** The country of the phone number (Example: "US") */
|
|
32
|
+
country: string;
|
|
33
|
+
|
|
34
|
+
/** The label for the phone number (Example: "Mobile") */
|
|
35
|
+
label: string;
|
|
36
|
+
|
|
37
|
+
/** The phone number itself (Example: "800000000") */
|
|
38
|
+
number: string;
|
|
39
|
+
|
|
40
|
+
/** Whether the phone number has been verified (Example: true) */
|
|
41
|
+
verified: boolean;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* See the full documentation below:
|
|
46
|
+
* https://developers.zoom.us/docs/api/users/#tag/users/GET/users/{userId}
|
|
47
|
+
*/
|
|
48
|
+
export interface ZoomProfile extends Record<string, any> {
|
|
49
|
+
/* cspell:disable-next-line */
|
|
50
|
+
/** The user's account ID (Example: "q6gBJVO5TzexKYTb_I2rpg") */
|
|
51
|
+
account_id: string;
|
|
52
|
+
/** The user's account number (Example: 10009239) */
|
|
53
|
+
account_number: number;
|
|
54
|
+
/** The user's cluster (Example: "us04") */
|
|
55
|
+
cluster: string;
|
|
56
|
+
/** The user's CMS ID. Only enabled for Kaltura integration (Example: "KDcuGIm1QgePTO8WbOqwIQ") */
|
|
57
|
+
cms_user_id: string;
|
|
58
|
+
/** The user's cost center (Example: "cost center") */
|
|
59
|
+
cost_center: string;
|
|
60
|
+
/** User create time (Example: "2018-10-31T04:32:37Z") */
|
|
61
|
+
created_at: string;
|
|
62
|
+
/** Department (Example: "Developers") */
|
|
63
|
+
dept: string;
|
|
64
|
+
/** User's display name (Example: "Jill Chill") */
|
|
65
|
+
display_name: string;
|
|
66
|
+
/** User's email address (Example: "jchill@example.com") */
|
|
67
|
+
email: string;
|
|
68
|
+
/** User's first name (Example: "Jill") */
|
|
69
|
+
first_name: string;
|
|
70
|
+
/* cspell:disable-next-line */
|
|
71
|
+
/** IDs of the web groups that the user belongs to (Example: ["RSMaSp8sTEGK0_oamiA2_w"]) */
|
|
72
|
+
group_ids: string[];
|
|
73
|
+
/* cspell:disable-next-line */
|
|
74
|
+
/** User ID (Example: "zJKyaiAyTNC-MWjiWC18KQ") */
|
|
75
|
+
id: string;
|
|
76
|
+
/* cspell:disable-next-line */
|
|
77
|
+
/** IM IDs of the groups that the user belongs to (Example: ["t-_-d56CSWG-7BF15LLrOw"]) */
|
|
78
|
+
im_group_ids: string[];
|
|
79
|
+
/** The user's JID (Example: "jchill@example.com") */
|
|
80
|
+
jid: string;
|
|
81
|
+
/** The user's job title (Example: "API Developer") */
|
|
82
|
+
job_title: string;
|
|
83
|
+
/** Default language for the Zoom Web Portal (Example: "en-US") */
|
|
84
|
+
language: string;
|
|
85
|
+
/** User last login client version (Example: "5.9.6.4993(mac)") */
|
|
86
|
+
last_client_version: string;
|
|
87
|
+
/** User last login time (Example: "2021-05-05T20:40:30Z") */
|
|
88
|
+
last_login_time: string;
|
|
89
|
+
/** User's last name (Example: "Chill") */
|
|
90
|
+
last_name: string;
|
|
91
|
+
/** The time zone of the user (Example: "Asia/Shanghai") */
|
|
92
|
+
timezone: string;
|
|
93
|
+
/** User's location (Example: "Paris") */
|
|
94
|
+
location: string;
|
|
95
|
+
/** The user's login method (Example: 101) */
|
|
96
|
+
login_types: LoginType[];
|
|
97
|
+
/** User's personal meeting URL (Example: "example.com") */
|
|
98
|
+
personal_meeting_url: string;
|
|
99
|
+
/** The URL for user's profile picture (Example: "example.com") */
|
|
100
|
+
pic_url: string;
|
|
101
|
+
/** Personal Meeting ID (PMI) (Example: 3542471135) */
|
|
102
|
+
pmi: number;
|
|
103
|
+
/** Unique identifier of the user's assigned role (Example: "0") */
|
|
104
|
+
role_id: string;
|
|
105
|
+
/** User's role name (Example: "Admin") */
|
|
106
|
+
role_name: string;
|
|
107
|
+
/** Status of user's account (Example: "pending") */
|
|
108
|
+
status: AccountStatus;
|
|
109
|
+
/** Use the personal meeting ID (PMI) for instant meetings (Example: false) */
|
|
110
|
+
use_pmi: boolean;
|
|
111
|
+
/** The time and date when the user was created (Example: "2018-10-31T04:32:37Z") */
|
|
112
|
+
user_created_at: string;
|
|
113
|
+
/** Displays whether user is verified or not (Example: 1) */
|
|
114
|
+
verified: number;
|
|
115
|
+
/** The user's Zoom Workplace plan option (Example: 64) */
|
|
116
|
+
zoom_one_type: number;
|
|
117
|
+
/** The user's company (Example: "Jill") */
|
|
118
|
+
company?: string | undefined;
|
|
119
|
+
/* cspell:disable-next-line */
|
|
120
|
+
/** Custom attributes that have been assigned to the user (Example: [{ "key": "cbf_cywdkexrtqc73f97gd4w6g", "name": "A1", "value": "1" }]) */
|
|
121
|
+
custom_attributes?:
|
|
122
|
+
| { key: string; name: string; value: string }[]
|
|
123
|
+
| undefined;
|
|
124
|
+
/* cspell:disable-next-line */
|
|
125
|
+
/** The employee's unique ID. This field only returns when SAML single sign-on (SSO) is enabled. The `login_type` value is `101` (SSO) (Example: "HqDyI037Qjili1kNsSIrIg") */
|
|
126
|
+
employee_unique_id?: string | undefined;
|
|
127
|
+
/** The manager for the user (Example: "thill@example.com") */
|
|
128
|
+
manager?: string | undefined;
|
|
129
|
+
/** The phone number's ISO country code (Example: "+1") */
|
|
130
|
+
phone_numbers?: PhoneNumber[] | undefined;
|
|
131
|
+
/** The user's plan type (Example: "1") */
|
|
132
|
+
plan_united_type?: string | undefined;
|
|
133
|
+
/** The user's pronouns (Example: "3123") */
|
|
134
|
+
pronouns?: string | undefined;
|
|
135
|
+
/** The user's display pronouns setting (Example: 1) */
|
|
136
|
+
pronouns_option?: PronounOption | undefined;
|
|
137
|
+
/** Personal meeting room URL, if the user has one (Example: "example.com") */
|
|
138
|
+
vanity_url?: string | undefined;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export interface ZoomOptions extends ProviderOptions<ZoomProfile> {
|
|
142
|
+
clientId: string;
|
|
143
|
+
pkce?: boolean | undefined;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export const zoom = (userOptions: ZoomOptions) => {
|
|
147
|
+
const options = {
|
|
148
|
+
pkce: true,
|
|
149
|
+
...userOptions,
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
return {
|
|
153
|
+
id: "zoom",
|
|
154
|
+
name: "Zoom",
|
|
155
|
+
createAuthorizationURL: async ({ state, redirectURI, codeVerifier }) => {
|
|
156
|
+
const params = new URLSearchParams({
|
|
157
|
+
response_type: "code",
|
|
158
|
+
redirect_uri: options.redirectURI ? options.redirectURI : redirectURI,
|
|
159
|
+
client_id: options.clientId,
|
|
160
|
+
state,
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
if (options.pkce) {
|
|
164
|
+
const codeChallenge = await generateCodeChallenge(codeVerifier);
|
|
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
|
+
},
|
|
174
|
+
validateAuthorizationCode: async ({ code, redirectURI, codeVerifier }) => {
|
|
175
|
+
return validateAuthorizationCode({
|
|
176
|
+
code,
|
|
177
|
+
redirectURI: options.redirectURI || redirectURI,
|
|
178
|
+
codeVerifier,
|
|
179
|
+
options,
|
|
180
|
+
tokenEndpoint: "https://zoom.us/oauth/token",
|
|
181
|
+
authentication: "post",
|
|
182
|
+
});
|
|
183
|
+
},
|
|
184
|
+
refreshAccessToken: options.refreshAccessToken
|
|
185
|
+
? options.refreshAccessToken
|
|
186
|
+
: async (refreshToken) =>
|
|
187
|
+
refreshAccessToken({
|
|
188
|
+
refreshToken,
|
|
189
|
+
options: {
|
|
190
|
+
clientId: options.clientId,
|
|
191
|
+
clientKey: options.clientKey,
|
|
192
|
+
clientSecret: options.clientSecret,
|
|
193
|
+
},
|
|
194
|
+
tokenEndpoint: "https://zoom.us/oauth/token",
|
|
195
|
+
}),
|
|
196
|
+
async getUserInfo(token) {
|
|
197
|
+
if (options.getUserInfo) {
|
|
198
|
+
return options.getUserInfo(token);
|
|
199
|
+
}
|
|
200
|
+
const { data: profile, error } = await betterFetch<ZoomProfile>(
|
|
201
|
+
"https://api.zoom.us/v2/users/me",
|
|
202
|
+
{
|
|
203
|
+
headers: {
|
|
204
|
+
authorization: `Bearer ${token.accessToken}`,
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
if (error) {
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const userMap = await options.mapProfileToUser?.(profile);
|
|
214
|
+
|
|
215
|
+
return {
|
|
216
|
+
user: {
|
|
217
|
+
id: profile.id,
|
|
218
|
+
name: profile.display_name,
|
|
219
|
+
image: profile.pic_url,
|
|
220
|
+
email: profile.email,
|
|
221
|
+
emailVerified: Boolean(profile.verified),
|
|
222
|
+
...userMap,
|
|
223
|
+
},
|
|
224
|
+
data: {
|
|
225
|
+
...profile,
|
|
226
|
+
},
|
|
227
|
+
};
|
|
228
|
+
},
|
|
229
|
+
} satisfies OAuthProvider<ZoomProfile>;
|
|
230
|
+
};
|