@gatwech/core 0.0.10 → 1.0.0-beta.18

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.
Files changed (130) hide show
  1. package/dist/api/index.d.mts +2 -2
  2. package/dist/context/index.d.mts +2 -2
  3. package/dist/db/adapter/index.d.mts +2 -2
  4. package/dist/db/index.d.mts +2 -2
  5. package/dist/env/index.d.mts +1 -1
  6. package/dist/env/index.mjs +1 -1
  7. package/dist/{env-JMSMESs1.mjs → env-4_Lym7sj.mjs} +7 -7
  8. package/dist/index-65G5U5DB.d.mts +3002 -0
  9. package/dist/{index-DLP-K0uY.d.mts → index-CmdhhvA2.d.mts} +3 -3
  10. package/dist/index.d.mts +3 -3
  11. package/dist/oauth2/index.d.mts +2 -2
  12. package/dist/social-providers/index.d.mts +3 -3
  13. package/dist/social-providers/index.mjs +71 -2412
  14. package/dist/src/api/index.d.ts +119 -0
  15. package/dist/src/async_hooks/index.d.ts +6 -0
  16. package/dist/src/context/endpoint-context.d.ts +14 -0
  17. package/dist/src/context/index.d.ts +3 -0
  18. package/dist/src/context/request-state.d.ts +13 -0
  19. package/dist/src/context/transaction.d.ts +11 -0
  20. package/dist/src/db/adapter/index.d.ts +401 -0
  21. package/{src/db/index.ts → dist/src/db/index.d.ts} +2 -18
  22. package/dist/src/db/plugin.d.ts +10 -0
  23. package/dist/src/db/schema/account.d.ts +22 -0
  24. package/dist/src/db/schema/rate-limit.d.ts +10 -0
  25. package/dist/src/db/schema/session.d.ts +17 -0
  26. package/dist/src/db/schema/shared.d.ts +6 -0
  27. package/dist/src/db/schema/user.d.ts +16 -0
  28. package/{src/db/schema/verification.ts → dist/src/db/schema/verification.d.ts} +8 -8
  29. package/dist/src/db/type.d.ts +159 -0
  30. package/dist/src/env/color-depth.d.ts +1 -0
  31. package/dist/src/env/env-impl.d.ts +29 -0
  32. package/dist/src/env/index.d.ts +3 -0
  33. package/dist/src/env/logger.d.ts +50 -0
  34. package/dist/src/error/codes.d.ts +27 -0
  35. package/dist/src/error/index.d.ts +4 -0
  36. package/dist/src/oauth2/client-credentials-token.d.ts +21 -0
  37. package/dist/src/oauth2/create-authorization-url.d.ts +21 -0
  38. package/dist/src/oauth2/index.d.ts +6 -0
  39. package/dist/src/oauth2/oauth-provider.d.ts +178 -0
  40. package/dist/src/oauth2/refresh-access-token.d.ts +20 -0
  41. package/dist/src/oauth2/utils.d.ts +3 -0
  42. package/dist/src/oauth2/validate-authorization-code.d.ts +28 -0
  43. package/dist/src/social-providers/github.d.ts +89 -0
  44. package/dist/src/social-providers/google.d.ts +82 -0
  45. package/dist/src/social-providers/index.d.ts +93 -0
  46. package/dist/src/types/context.d.ts +177 -0
  47. package/dist/src/types/cookie.d.ts +15 -0
  48. package/dist/src/types/helper.d.ts +9 -0
  49. package/dist/src/types/index.d.ts +7 -0
  50. package/dist/src/types/init-options.d.ts +1140 -0
  51. package/dist/src/types/plugin-client.d.ts +88 -0
  52. package/dist/src/types/plugin.d.ts +120 -0
  53. package/dist/src/utils/error-codes.d.ts +9 -0
  54. package/package.json +11 -5
  55. package/.turbo/turbo-build.log +0 -42
  56. package/dist/index-DjrJweYn.d.mts +0 -7312
  57. package/src/api/index.ts +0 -57
  58. package/src/async_hooks/index.ts +0 -35
  59. package/src/context/endpoint-context.ts +0 -48
  60. package/src/context/index.ts +0 -21
  61. package/src/context/request-state.test.ts +0 -346
  62. package/src/context/request-state.ts +0 -75
  63. package/src/context/transaction.ts +0 -72
  64. package/src/db/adapter/index.ts +0 -466
  65. package/src/db/plugin.ts +0 -11
  66. package/src/db/schema/account.ts +0 -34
  67. package/src/db/schema/rate-limit.ts +0 -21
  68. package/src/db/schema/session.ts +0 -17
  69. package/src/db/schema/shared.ts +0 -7
  70. package/src/db/schema/user.ts +0 -16
  71. package/src/db/type.ts +0 -180
  72. package/src/env/color-depth.ts +0 -172
  73. package/src/env/env-impl.ts +0 -124
  74. package/src/env/index.ts +0 -23
  75. package/src/env/logger.test.ts +0 -33
  76. package/src/env/logger.ts +0 -145
  77. package/src/error/codes.ts +0 -31
  78. package/src/error/index.ts +0 -11
  79. package/src/oauth2/client-credentials-token.ts +0 -102
  80. package/src/oauth2/create-authorization-url.ts +0 -85
  81. package/src/oauth2/index.ts +0 -21
  82. package/src/oauth2/oauth-provider.ts +0 -211
  83. package/src/oauth2/refresh-access-token.ts +0 -124
  84. package/src/oauth2/utils.ts +0 -36
  85. package/src/oauth2/validate-authorization-code.ts +0 -154
  86. package/src/social-providers/apple.ts +0 -213
  87. package/src/social-providers/atlassian.ts +0 -132
  88. package/src/social-providers/cognito.ts +0 -269
  89. package/src/social-providers/discord.ts +0 -169
  90. package/src/social-providers/dropbox.ts +0 -112
  91. package/src/social-providers/facebook.ts +0 -204
  92. package/src/social-providers/figma.ts +0 -115
  93. package/src/social-providers/github.ts +0 -154
  94. package/src/social-providers/gitlab.ts +0 -152
  95. package/src/social-providers/google.ts +0 -171
  96. package/src/social-providers/huggingface.ts +0 -118
  97. package/src/social-providers/index.ts +0 -124
  98. package/src/social-providers/kakao.ts +0 -178
  99. package/src/social-providers/kick.ts +0 -92
  100. package/src/social-providers/line.ts +0 -169
  101. package/src/social-providers/linear.ts +0 -120
  102. package/src/social-providers/linkedin.ts +0 -110
  103. package/src/social-providers/microsoft-entra-id.ts +0 -245
  104. package/src/social-providers/naver.ts +0 -112
  105. package/src/social-providers/notion.ts +0 -108
  106. package/src/social-providers/paybin.ts +0 -122
  107. package/src/social-providers/paypal.ts +0 -263
  108. package/src/social-providers/polar.ts +0 -107
  109. package/src/social-providers/reddit.ts +0 -122
  110. package/src/social-providers/roblox.ts +0 -110
  111. package/src/social-providers/salesforce.ts +0 -159
  112. package/src/social-providers/slack.ts +0 -111
  113. package/src/social-providers/spotify.ts +0 -93
  114. package/src/social-providers/tiktok.ts +0 -210
  115. package/src/social-providers/twitch.ts +0 -111
  116. package/src/social-providers/twitter.ts +0 -198
  117. package/src/social-providers/vk.ts +0 -126
  118. package/src/social-providers/zoom.ts +0 -217
  119. package/src/types/context.ts +0 -269
  120. package/src/types/cookie.ts +0 -7
  121. package/src/types/helper.ts +0 -6
  122. package/src/types/index.ts +0 -21
  123. package/src/types/init-options.ts +0 -1346
  124. package/src/types/plugin-client.ts +0 -100
  125. package/src/types/plugin.ts +0 -158
  126. package/src/utils/error-codes.ts +0 -51
  127. package/tsconfig.json +0 -7
  128. package/tsdown.config.ts +0 -20
  129. /package/{src/index.ts → dist/src/index.d.ts} +0 -0
  130. /package/{src/utils/index.ts → dist/src/utils/index.d.ts} +0 -0
@@ -1,60 +1,40 @@
1
- import { i as logger } from "../env-JMSMESs1.mjs";
1
+ import { i as logger } from "../env-4_Lym7sj.mjs";
2
2
  import "../utils-BFQCAfNW.mjs";
3
3
  import { t as PayvoAuthError } from "../error-41YsFQ8b.mjs";
4
- import { a as refreshAccessToken, c as getOAuth2Tokens, n as validateAuthorizationCode, o as createAuthorizationURL, s as generateCodeChallenge } from "../oauth2-DyI7_CNv.mjs";
5
- import { APIError } from "better-call";
4
+ import { a as refreshAccessToken, n as validateAuthorizationCode, o as createAuthorizationURL } from "../oauth2-DyI7_CNv.mjs";
6
5
  import * as z$1 from "zod";
7
- import { base64 } from "@gatwech/utils/base64";
8
6
  import { betterFetch } from "@better-fetch/fetch";
9
- import { createRemoteJWKSet, decodeJwt, decodeProtectedHeader, importJWK, jwtVerify } from "jose";
7
+ import { decodeJwt } from "jose";
10
8
 
11
- //#region src/social-providers/apple.ts
12
- const apple = (options) => {
13
- const tokenEndpoint = "https://appleid.apple.com/auth/token";
9
+ //#region src/social-providers/github.ts
10
+ const github = (options) => {
11
+ const tokenEndpoint = "https://github.com/login/oauth/access_token";
14
12
  return {
15
- id: "apple",
16
- name: "Apple",
17
- async createAuthorizationURL({ state, scopes, redirectURI }) {
18
- const _scope = options.disableDefaultScope ? [] : ["email", "name"];
19
- if (options.scope) _scope.push(...options.scope);
20
- if (scopes) _scope.push(...scopes);
21
- return await createAuthorizationURL({
22
- id: "apple",
13
+ id: "github",
14
+ name: "GitHub",
15
+ createAuthorizationURL({ state, scopes, loginHint, redirectURI }) {
16
+ const _scopes = options.disableDefaultScope ? [] : ["read:user", "user:email"];
17
+ if (options.scope) _scopes.push(...options.scope);
18
+ if (scopes) _scopes.push(...scopes);
19
+ return createAuthorizationURL({
20
+ id: "github",
23
21
  options,
24
- authorizationEndpoint: "https://appleid.apple.com/auth/authorize",
25
- scopes: _scope,
22
+ authorizationEndpoint: "https://github.com/login/oauth/authorize",
23
+ scopes: _scopes,
26
24
  state,
27
25
  redirectURI,
28
- responseMode: "form_post",
29
- responseType: "code id_token"
26
+ loginHint,
27
+ prompt: options.prompt
30
28
  });
31
29
  },
32
- validateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {
30
+ validateAuthorizationCode: async ({ code, redirectURI }) => {
33
31
  return validateAuthorizationCode({
34
32
  code,
35
- codeVerifier,
36
33
  redirectURI,
37
34
  options,
38
35
  tokenEndpoint
39
36
  });
40
37
  },
41
- async verifyIdToken(token, nonce) {
42
- if (options.disableIdTokenSignIn) return false;
43
- if (options.verifyIdToken) return options.verifyIdToken(token, nonce);
44
- const { kid, alg: jwtAlg } = decodeProtectedHeader(token);
45
- if (!kid || !jwtAlg) return false;
46
- const { payload: jwtClaims } = await jwtVerify(token, await getApplePublicKey(kid), {
47
- algorithms: [jwtAlg],
48
- issuer: "https://appleid.apple.com",
49
- audience: options.audience && options.audience.length ? options.audience : options.appBundleIdentifier ? options.appBundleIdentifier : options.clientId,
50
- maxTokenAge: "1h"
51
- });
52
- ["email_verified", "is_private_email"].forEach((field) => {
53
- if (jwtClaims[field] !== void 0) jwtClaims[field] = Boolean(jwtClaims[field]);
54
- });
55
- if (nonce && jwtClaims.nonce !== nonce) return false;
56
- return !!jwtClaims;
57
- },
58
38
  refreshAccessToken: options.refreshAccessToken ? options.refreshAccessToken : async (refreshToken) => {
59
39
  return refreshAccessToken({
60
40
  refreshToken,
@@ -63,155 +43,72 @@ const apple = (options) => {
63
43
  clientKey: options.clientKey,
64
44
  clientSecret: options.clientSecret
65
45
  },
66
- tokenEndpoint: "https://appleid.apple.com/auth/token"
46
+ tokenEndpoint: "https://github.com/login/oauth/access_token"
67
47
  });
68
48
  },
69
49
  async getUserInfo(token) {
70
50
  if (options.getUserInfo) return options.getUserInfo(token);
71
- if (!token.idToken) return null;
72
- const profile = decodeJwt(token.idToken);
73
- if (!profile) return null;
74
- const name = token.user ? `${token.user.name?.firstName} ${token.user.name?.lastName}` : profile.name || profile.email;
75
- const emailVerified = typeof profile.email_verified === "boolean" ? profile.email_verified : profile.email_verified === "true";
76
- const enrichedProfile = {
77
- ...profile,
78
- name
79
- };
80
- const userMap = await options.mapProfileToUser?.(enrichedProfile);
51
+ const { data: profile, error } = await betterFetch("https://api.github.com/user", { headers: {
52
+ "User-Agent": "payvo-auth",
53
+ authorization: `Bearer ${token.accessToken}`
54
+ } });
55
+ if (error) return null;
56
+ const { data: emails } = await betterFetch("https://api.github.com/user/emails", { headers: {
57
+ Authorization: `Bearer ${token.accessToken}`,
58
+ "User-Agent": "payvo-auth"
59
+ } });
60
+ if (!profile.email && emails) profile.email = (emails.find((e) => e.primary) ?? emails[0])?.email;
61
+ const emailVerified = emails?.find((e) => e.email === profile.email)?.verified ?? false;
62
+ const userMap = await options.mapProfileToUser?.(profile);
81
63
  return {
82
64
  user: {
83
- id: profile.sub,
84
- name: enrichedProfile.name,
85
- emailVerified,
65
+ id: profile.id,
66
+ name: profile.name || profile.login,
86
67
  email: profile.email,
68
+ image: profile.avatar_url,
69
+ emailVerified,
87
70
  ...userMap
88
71
  },
89
- data: enrichedProfile
72
+ data: profile
90
73
  };
91
74
  },
92
75
  options
93
76
  };
94
77
  };
95
- const getApplePublicKey = async (kid) => {
96
- const { data } = await betterFetch(`https://appleid.apple.com/auth/keys`);
97
- if (!data?.keys) throw new APIError("BAD_REQUEST", { message: "Keys not found" });
98
- const jwk = data.keys.find((key) => key.kid === kid);
99
- if (!jwk) throw new Error(`JWK with kid ${kid} not found`);
100
- return await importJWK(jwk, jwk.alg);
101
- };
102
78
 
103
79
  //#endregion
104
- //#region src/social-providers/atlassian.ts
105
- const atlassian = (options) => {
80
+ //#region src/social-providers/google.ts
81
+ const google = (options) => {
106
82
  return {
107
- id: "atlassian",
108
- name: "Atlassian",
109
- async createAuthorizationURL({ state, scopes, codeVerifier, redirectURI }) {
83
+ id: "google",
84
+ name: "Google",
85
+ async createAuthorizationURL({ state, scopes, codeVerifier, redirectURI, loginHint, display }) {
110
86
  if (!options.clientId || !options.clientSecret) {
111
- logger.error("Client Id and Secret are required for Atlassian");
112
- throw new PayvoAuthError("CLIENT_ID_AND_SECRET_REQUIRED");
113
- }
114
- if (!codeVerifier) throw new PayvoAuthError("codeVerifier is required for Atlassian");
115
- const _scopes = options.disableDefaultScope ? [] : ["read:jira-user", "offline_access"];
116
- if (options.scope) _scopes.push(...options.scope);
117
- if (scopes) _scopes.push(...scopes);
118
- return createAuthorizationURL({
119
- id: "atlassian",
120
- options,
121
- authorizationEndpoint: "https://auth.atlassian.com/authorize",
122
- scopes: _scopes,
123
- state,
124
- codeVerifier,
125
- redirectURI,
126
- additionalParams: { audience: "api.atlassian.com" },
127
- prompt: options.prompt
128
- });
129
- },
130
- validateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {
131
- return validateAuthorizationCode({
132
- code,
133
- codeVerifier,
134
- redirectURI,
135
- options,
136
- tokenEndpoint: "https://auth.atlassian.com/oauth/token"
137
- });
138
- },
139
- refreshAccessToken: options.refreshAccessToken ? options.refreshAccessToken : async (refreshToken) => {
140
- return refreshAccessToken({
141
- refreshToken,
142
- options: {
143
- clientId: options.clientId,
144
- clientSecret: options.clientSecret
145
- },
146
- tokenEndpoint: "https://auth.atlassian.com/oauth/token"
147
- });
148
- },
149
- async getUserInfo(token) {
150
- if (options.getUserInfo) return options.getUserInfo(token);
151
- if (!token.accessToken) return null;
152
- try {
153
- const { data: profile } = await betterFetch("https://api.atlassian.com/me", { headers: { Authorization: `Bearer ${token.accessToken}` } });
154
- if (!profile) return null;
155
- const userMap = await options.mapProfileToUser?.(profile);
156
- return {
157
- user: {
158
- id: profile.account_id,
159
- name: profile.name,
160
- email: profile.email,
161
- image: profile.picture,
162
- emailVerified: false,
163
- ...userMap
164
- },
165
- data: profile
166
- };
167
- } catch (error) {
168
- logger.error("Failed to fetch user info from Figma:", error);
169
- return null;
170
- }
171
- },
172
- options
173
- };
174
- };
175
-
176
- //#endregion
177
- //#region src/social-providers/cognito.ts
178
- const cognito = (options) => {
179
- if (!options.domain || !options.region || !options.userPoolId) {
180
- logger.error("Domain, region and userPoolId are required for Amazon Cognito. Make sure to provide them in the options.");
181
- throw new PayvoAuthError("DOMAIN_AND_REGION_REQUIRED");
182
- }
183
- const cleanDomain = options.domain.replace(/^https?:\/\//, "");
184
- const authorizationEndpoint = `https://${cleanDomain}/oauth2/authorize`;
185
- const tokenEndpoint = `https://${cleanDomain}/oauth2/token`;
186
- const userInfoEndpoint = `https://${cleanDomain}/oauth2/userinfo`;
187
- return {
188
- id: "cognito",
189
- name: "Cognito",
190
- async createAuthorizationURL({ state, scopes, codeVerifier, redirectURI }) {
191
- if (!options.clientId) {
192
- logger.error("ClientId is required for Amazon Cognito. Make sure to provide them in the options.");
87
+ logger.error("Client Id and Client Secret is required for Google. Make sure to provide them in the options.");
193
88
  throw new PayvoAuthError("CLIENT_ID_AND_SECRET_REQUIRED");
194
89
  }
195
- if (options.requireClientSecret && !options.clientSecret) {
196
- logger.error("Client Secret is required when requireClientSecret is true. Make sure to provide it in the options.");
197
- throw new PayvoAuthError("CLIENT_SECRET_REQUIRED");
198
- }
90
+ if (!codeVerifier) throw new PayvoAuthError("codeVerifier is required for Google");
199
91
  const _scopes = options.disableDefaultScope ? [] : [
200
- "openid",
92
+ "email",
201
93
  "profile",
202
- "email"
94
+ "openid"
203
95
  ];
204
96
  if (options.scope) _scopes.push(...options.scope);
205
97
  if (scopes) _scopes.push(...scopes);
206
98
  return await createAuthorizationURL({
207
- id: "cognito",
208
- options: { ...options },
209
- authorizationEndpoint,
99
+ id: "google",
100
+ options,
101
+ authorizationEndpoint: "https://accounts.google.com/o/oauth2/auth",
210
102
  scopes: _scopes,
211
103
  state,
212
104
  codeVerifier,
213
105
  redirectURI,
214
- prompt: options.prompt
106
+ prompt: options.prompt,
107
+ accessType: options.accessType,
108
+ display: display || options.display,
109
+ loginHint,
110
+ hd: options.hd,
111
+ additionalParams: { include_granted_scopes: "true" }
215
112
  });
216
113
  },
217
114
  validateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {
@@ -220,7 +117,7 @@ const cognito = (options) => {
220
117
  codeVerifier,
221
118
  redirectURI,
222
119
  options,
223
- tokenEndpoint
120
+ tokenEndpoint: "https://oauth2.googleapis.com/token"
224
121
  });
225
122
  },
226
123
  refreshAccessToken: options.refreshAccessToken ? options.refreshAccessToken : async (refreshToken) => {
@@ -231,2283 +128,45 @@ const cognito = (options) => {
231
128
  clientKey: options.clientKey,
232
129
  clientSecret: options.clientSecret
233
130
  },
234
- tokenEndpoint
131
+ tokenEndpoint: "https://www.googleapis.com/oauth2/v4/token"
235
132
  });
236
133
  },
237
134
  async verifyIdToken(token, nonce) {
238
135
  if (options.disableIdTokenSignIn) return false;
239
136
  if (options.verifyIdToken) return options.verifyIdToken(token, nonce);
240
- try {
241
- const { kid, alg: jwtAlg } = decodeProtectedHeader(token);
242
- if (!kid || !jwtAlg) return false;
243
- const publicKey = await getCognitoPublicKey(kid, options.region, options.userPoolId);
244
- const expectedIssuer = `https://cognito-idp.${options.region}.amazonaws.com/${options.userPoolId}`;
245
- const { payload: jwtClaims } = await jwtVerify(token, publicKey, {
246
- algorithms: [jwtAlg],
247
- issuer: expectedIssuer,
248
- audience: options.clientId,
249
- maxTokenAge: "1h"
250
- });
251
- if (nonce && jwtClaims.nonce !== nonce) return false;
252
- return true;
253
- } catch (error) {
254
- logger.error("Failed to verify ID token:", error);
255
- return false;
256
- }
257
- },
258
- async getUserInfo(token) {
259
- if (options.getUserInfo) return options.getUserInfo(token);
260
- if (token.idToken) try {
261
- const profile = decodeJwt(token.idToken);
262
- if (!profile) return null;
263
- const name = profile.name || profile.given_name || profile.username || profile.email;
264
- const enrichedProfile = {
265
- ...profile,
266
- name
267
- };
268
- const userMap = await options.mapProfileToUser?.(enrichedProfile);
269
- return {
270
- user: {
271
- id: profile.sub,
272
- name: enrichedProfile.name,
273
- email: profile.email,
274
- image: profile.picture,
275
- emailVerified: profile.email_verified,
276
- ...userMap
277
- },
278
- data: enrichedProfile
279
- };
280
- } catch (error) {
281
- logger.error("Failed to decode ID token:", error);
282
- }
283
- if (token.accessToken) try {
284
- const { data: userInfo } = await betterFetch(userInfoEndpoint, { headers: { Authorization: `Bearer ${token.accessToken}` } });
285
- if (userInfo) {
286
- const userMap = await options.mapProfileToUser?.(userInfo);
287
- return {
288
- user: {
289
- id: userInfo.sub,
290
- name: userInfo.name || userInfo.given_name || userInfo.username,
291
- email: userInfo.email,
292
- image: userInfo.picture,
293
- emailVerified: userInfo.email_verified,
294
- ...userMap
295
- },
296
- data: userInfo
297
- };
298
- }
299
- } catch (error) {
300
- logger.error("Failed to fetch user info from Cognito:", error);
301
- }
302
- return null;
303
- },
304
- options
305
- };
306
- };
307
- const getCognitoPublicKey = async (kid, region, userPoolId) => {
308
- const COGNITO_JWKS_URI = `https://cognito-idp.${region}.amazonaws.com/${userPoolId}/.well-known/jwks.json`;
309
- try {
310
- const { data } = await betterFetch(COGNITO_JWKS_URI);
311
- if (!data?.keys) throw new APIError("BAD_REQUEST", { message: "Keys not found" });
312
- const jwk = data.keys.find((key) => key.kid === kid);
313
- if (!jwk) throw new Error(`JWK with kid ${kid} not found`);
314
- return await importJWK(jwk, jwk.alg);
315
- } catch (error) {
316
- logger.error("Failed to fetch Cognito public key:", error);
317
- throw error;
318
- }
319
- };
320
-
321
- //#endregion
322
- //#region src/social-providers/discord.ts
323
- const discord = (options) => {
324
- return {
325
- id: "discord",
326
- name: "Discord",
327
- createAuthorizationURL({ state, scopes, redirectURI }) {
328
- const _scopes = options.disableDefaultScope ? [] : ["identify", "email"];
329
- if (scopes) _scopes.push(...scopes);
330
- if (options.scope) _scopes.push(...options.scope);
331
- const permissionsParam = _scopes.includes("bot") && options.permissions !== void 0 ? `&permissions=${options.permissions}` : "";
332
- return new URL(`https://discord.com/api/oauth2/authorize?scope=${_scopes.join("+")}&response_type=code&client_id=${options.clientId}&redirect_uri=${encodeURIComponent(options.redirectURI || redirectURI)}&state=${state}&prompt=${options.prompt || "none"}${permissionsParam}`);
333
- },
334
- validateAuthorizationCode: async ({ code, redirectURI }) => {
335
- return validateAuthorizationCode({
336
- code,
337
- redirectURI,
338
- options,
339
- tokenEndpoint: "https://discord.com/api/oauth2/token"
340
- });
341
- },
342
- refreshAccessToken: options.refreshAccessToken ? options.refreshAccessToken : async (refreshToken) => {
343
- return refreshAccessToken({
344
- refreshToken,
345
- options: {
346
- clientId: options.clientId,
347
- clientKey: options.clientKey,
348
- clientSecret: options.clientSecret
349
- },
350
- tokenEndpoint: "https://discord.com/api/oauth2/token"
351
- });
352
- },
353
- async getUserInfo(token) {
354
- if (options.getUserInfo) return options.getUserInfo(token);
355
- const { data: profile, error } = await betterFetch("https://discord.com/api/users/@me", { headers: { authorization: `Bearer ${token.accessToken}` } });
356
- if (error) return null;
357
- if (profile.avatar === null) profile.image_url = `https://cdn.discordapp.com/embed/avatars/${profile.discriminator === "0" ? Number(BigInt(profile.id) >> BigInt(22)) % 6 : parseInt(profile.discriminator) % 5}.png`;
358
- else {
359
- const format = profile.avatar.startsWith("a_") ? "gif" : "png";
360
- profile.image_url = `https://cdn.discordapp.com/avatars/${profile.id}/${profile.avatar}.${format}`;
361
- }
362
- const userMap = await options.mapProfileToUser?.(profile);
363
- return {
364
- user: {
365
- id: profile.id,
366
- name: profile.global_name || profile.username || "",
367
- email: profile.email,
368
- emailVerified: profile.verified,
369
- image: profile.image_url,
370
- ...userMap
371
- },
372
- data: profile
373
- };
374
- },
375
- options
376
- };
377
- };
378
-
379
- //#endregion
380
- //#region src/social-providers/dropbox.ts
381
- const dropbox = (options) => {
382
- const tokenEndpoint = "https://api.dropboxapi.com/oauth2/token";
383
- return {
384
- id: "dropbox",
385
- name: "Dropbox",
386
- createAuthorizationURL: async ({ state, scopes, codeVerifier, redirectURI }) => {
387
- const _scopes = options.disableDefaultScope ? [] : ["account_info.read"];
388
- if (options.scope) _scopes.push(...options.scope);
389
- if (scopes) _scopes.push(...scopes);
390
- const additionalParams = {};
391
- if (options.accessType) additionalParams.token_access_type = options.accessType;
392
- return await createAuthorizationURL({
393
- id: "dropbox",
394
- options,
395
- authorizationEndpoint: "https://www.dropbox.com/oauth2/authorize",
396
- scopes: _scopes,
397
- state,
398
- redirectURI,
399
- codeVerifier,
400
- additionalParams
401
- });
402
- },
403
- validateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {
404
- return await validateAuthorizationCode({
405
- code,
406
- codeVerifier,
407
- redirectURI,
408
- options,
409
- tokenEndpoint
410
- });
411
- },
412
- refreshAccessToken: options.refreshAccessToken ? options.refreshAccessToken : async (refreshToken) => {
413
- return refreshAccessToken({
414
- refreshToken,
415
- options: {
416
- clientId: options.clientId,
417
- clientKey: options.clientKey,
418
- clientSecret: options.clientSecret
419
- },
420
- tokenEndpoint: "https://api.dropbox.com/oauth2/token"
421
- });
137
+ const { data: tokenInfo } = await betterFetch(`https://www.googleapis.com/oauth2/v3/tokeninfo?id_token=${token}`);
138
+ if (!tokenInfo) return false;
139
+ return tokenInfo.aud === options.clientId && (tokenInfo.iss === "https://accounts.google.com" || tokenInfo.iss === "accounts.google.com");
422
140
  },
423
141
  async getUserInfo(token) {
424
142
  if (options.getUserInfo) return options.getUserInfo(token);
425
- const { data: profile, error } = await betterFetch("https://api.dropboxapi.com/2/users/get_current_account", {
426
- method: "POST",
427
- headers: { Authorization: `Bearer ${token.accessToken}` }
428
- });
429
- if (error) return null;
430
- const userMap = await options.mapProfileToUser?.(profile);
143
+ if (!token.idToken) return null;
144
+ const user = decodeJwt(token.idToken);
145
+ const userMap = await options.mapProfileToUser?.(user);
431
146
  return {
432
147
  user: {
433
- id: profile.account_id,
434
- name: profile.name?.display_name,
435
- email: profile.email,
436
- emailVerified: profile.email_verified || false,
437
- image: profile.profile_photo_url,
148
+ id: user.sub,
149
+ name: user.name,
150
+ email: user.email,
151
+ image: user.picture,
152
+ emailVerified: user.email_verified,
438
153
  ...userMap
439
154
  },
440
- data: profile
155
+ data: user
441
156
  };
442
157
  },
443
158
  options
444
159
  };
445
160
  };
446
161
 
447
- //#endregion
448
- //#region src/social-providers/facebook.ts
449
- const facebook = (options) => {
450
- return {
451
- id: "facebook",
452
- name: "Facebook",
453
- async createAuthorizationURL({ state, scopes, redirectURI, loginHint }) {
454
- const _scopes = options.disableDefaultScope ? [] : ["email", "public_profile"];
455
- if (options.scope) _scopes.push(...options.scope);
456
- if (scopes) _scopes.push(...scopes);
457
- return await createAuthorizationURL({
458
- id: "facebook",
459
- options,
460
- authorizationEndpoint: "https://www.facebook.com/v21.0/dialog/oauth",
461
- scopes: _scopes,
462
- state,
463
- redirectURI,
464
- loginHint,
465
- additionalParams: options.configId ? { config_id: options.configId } : {}
466
- });
467
- },
468
- validateAuthorizationCode: async ({ code, redirectURI }) => {
469
- return validateAuthorizationCode({
470
- code,
471
- redirectURI,
472
- options,
473
- tokenEndpoint: "https://graph.facebook.com/oauth/access_token"
474
- });
475
- },
476
- async verifyIdToken(token, nonce) {
477
- if (options.disableIdTokenSignIn) return false;
478
- if (options.verifyIdToken) return options.verifyIdToken(token, nonce);
479
- if (token.split(".").length === 3) try {
480
- const { payload: jwtClaims } = await jwtVerify(token, createRemoteJWKSet(new URL("https://limited.facebook.com/.well-known/oauth/openid/jwks/")), {
481
- algorithms: ["RS256"],
482
- audience: options.clientId,
483
- issuer: "https://www.facebook.com"
484
- });
485
- if (nonce && jwtClaims.nonce !== nonce) return false;
486
- return !!jwtClaims;
487
- } catch (error) {
488
- return false;
489
- }
490
- return true;
491
- },
492
- refreshAccessToken: options.refreshAccessToken ? options.refreshAccessToken : async (refreshToken) => {
493
- return refreshAccessToken({
494
- refreshToken,
495
- options: {
496
- clientId: options.clientId,
497
- clientKey: options.clientKey,
498
- clientSecret: options.clientSecret
499
- },
500
- tokenEndpoint: "https://graph.facebook.com/v18.0/oauth/access_token"
501
- });
502
- },
503
- async getUserInfo(token) {
504
- if (options.getUserInfo) return options.getUserInfo(token);
505
- if (token.idToken && token.idToken.split(".").length === 3) {
506
- const profile$1 = decodeJwt(token.idToken);
507
- const user = {
508
- id: profile$1.sub,
509
- name: profile$1.name,
510
- email: profile$1.email,
511
- picture: { data: {
512
- url: profile$1.picture,
513
- height: 100,
514
- width: 100,
515
- is_silhouette: false
516
- } }
517
- };
518
- const userMap$1 = await options.mapProfileToUser?.({
519
- ...user,
520
- email_verified: true
521
- });
522
- return {
523
- user: {
524
- ...user,
525
- emailVerified: true,
526
- ...userMap$1
527
- },
528
- data: profile$1
529
- };
530
- }
531
- const { data: profile, error } = await betterFetch("https://graph.facebook.com/me?fields=" + [
532
- "id",
533
- "name",
534
- "email",
535
- "picture",
536
- ...options?.fields || []
537
- ].join(","), { auth: {
538
- type: "Bearer",
539
- token: token.accessToken
540
- } });
541
- if (error) return null;
542
- const userMap = await options.mapProfileToUser?.(profile);
543
- return {
544
- user: {
545
- id: profile.id,
546
- name: profile.name,
547
- email: profile.email,
548
- image: profile.picture.data.url,
549
- emailVerified: profile.email_verified,
550
- ...userMap
551
- },
552
- data: profile
553
- };
554
- },
555
- options
556
- };
557
- };
558
-
559
- //#endregion
560
- //#region src/social-providers/figma.ts
561
- const figma = (options) => {
562
- return {
563
- id: "figma",
564
- name: "Figma",
565
- async createAuthorizationURL({ state, scopes, codeVerifier, redirectURI }) {
566
- if (!options.clientId || !options.clientSecret) {
567
- logger.error("Client Id and Client Secret are required for Figma. Make sure to provide them in the options.");
568
- throw new PayvoAuthError("CLIENT_ID_AND_SECRET_REQUIRED");
569
- }
570
- if (!codeVerifier) throw new PayvoAuthError("codeVerifier is required for Figma");
571
- const _scopes = options.disableDefaultScope ? [] : ["file_read"];
572
- if (options.scope) _scopes.push(...options.scope);
573
- if (scopes) _scopes.push(...scopes);
574
- return await createAuthorizationURL({
575
- id: "figma",
576
- options,
577
- authorizationEndpoint: "https://www.figma.com/oauth",
578
- scopes: _scopes,
579
- state,
580
- codeVerifier,
581
- redirectURI
582
- });
583
- },
584
- validateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {
585
- return validateAuthorizationCode({
586
- code,
587
- codeVerifier,
588
- redirectURI,
589
- options,
590
- tokenEndpoint: "https://www.figma.com/api/oauth/token"
591
- });
592
- },
593
- refreshAccessToken: options.refreshAccessToken ? options.refreshAccessToken : async (refreshToken) => {
594
- return refreshAccessToken({
595
- refreshToken,
596
- options: {
597
- clientId: options.clientId,
598
- clientKey: options.clientKey,
599
- clientSecret: options.clientSecret
600
- },
601
- tokenEndpoint: "https://www.figma.com/api/oauth/token"
602
- });
603
- },
604
- async getUserInfo(token) {
605
- if (options.getUserInfo) return options.getUserInfo(token);
606
- try {
607
- const { data: profile } = await betterFetch("https://api.figma.com/v1/me", { headers: { Authorization: `Bearer ${token.accessToken}` } });
608
- if (!profile) {
609
- logger.error("Failed to fetch user from Figma");
610
- return null;
611
- }
612
- const userMap = await options.mapProfileToUser?.(profile);
613
- return {
614
- user: {
615
- id: profile.id,
616
- name: profile.handle,
617
- email: profile.email,
618
- image: profile.img_url,
619
- emailVerified: !!profile.email,
620
- ...userMap
621
- },
622
- data: profile
623
- };
624
- } catch (error) {
625
- logger.error("Failed to fetch user info from Figma:", error);
626
- return null;
627
- }
628
- },
629
- options
630
- };
631
- };
632
-
633
- //#endregion
634
- //#region src/social-providers/github.ts
635
- const github = (options) => {
636
- const tokenEndpoint = "https://github.com/login/oauth/access_token";
637
- return {
638
- id: "github",
639
- name: "GitHub",
640
- createAuthorizationURL({ state, scopes, loginHint, redirectURI }) {
641
- const _scopes = options.disableDefaultScope ? [] : ["read:user", "user:email"];
642
- if (options.scope) _scopes.push(...options.scope);
643
- if (scopes) _scopes.push(...scopes);
644
- return createAuthorizationURL({
645
- id: "github",
646
- options,
647
- authorizationEndpoint: "https://github.com/login/oauth/authorize",
648
- scopes: _scopes,
649
- state,
650
- redirectURI,
651
- loginHint,
652
- prompt: options.prompt
653
- });
654
- },
655
- validateAuthorizationCode: async ({ code, redirectURI }) => {
656
- return validateAuthorizationCode({
657
- code,
658
- redirectURI,
659
- options,
660
- tokenEndpoint
661
- });
662
- },
663
- refreshAccessToken: options.refreshAccessToken ? options.refreshAccessToken : async (refreshToken) => {
664
- return refreshAccessToken({
665
- refreshToken,
666
- options: {
667
- clientId: options.clientId,
668
- clientKey: options.clientKey,
669
- clientSecret: options.clientSecret
670
- },
671
- tokenEndpoint: "https://github.com/login/oauth/access_token"
672
- });
673
- },
674
- async getUserInfo(token) {
675
- if (options.getUserInfo) return options.getUserInfo(token);
676
- const { data: profile, error } = await betterFetch("https://api.github.com/user", { headers: {
677
- "User-Agent": "gatwech",
678
- authorization: `Bearer ${token.accessToken}`
679
- } });
680
- if (error) return null;
681
- const { data: emails } = await betterFetch("https://api.github.com/user/emails", { headers: {
682
- Authorization: `Bearer ${token.accessToken}`,
683
- "User-Agent": "gatwech"
684
- } });
685
- if (!profile.email && emails) profile.email = (emails.find((e) => e.primary) ?? emails[0])?.email;
686
- const emailVerified = emails?.find((e) => e.email === profile.email)?.verified ?? false;
687
- const userMap = await options.mapProfileToUser?.(profile);
688
- return {
689
- user: {
690
- id: profile.id,
691
- name: profile.name || profile.login,
692
- email: profile.email,
693
- image: profile.avatar_url,
694
- emailVerified,
695
- ...userMap
696
- },
697
- data: profile
698
- };
699
- },
700
- options
701
- };
702
- };
703
-
704
- //#endregion
705
- //#region src/social-providers/gitlab.ts
706
- const cleanDoubleSlashes = (input = "") => {
707
- return input.split("://").map((str) => str.replace(/\/{2,}/g, "/")).join("://");
708
- };
709
- const issuerToEndpoints = (issuer) => {
710
- let baseUrl = issuer || "https://gitlab.com";
711
- return {
712
- authorizationEndpoint: cleanDoubleSlashes(`${baseUrl}/oauth/authorize`),
713
- tokenEndpoint: cleanDoubleSlashes(`${baseUrl}/oauth/token`),
714
- userinfoEndpoint: cleanDoubleSlashes(`${baseUrl}/api/v4/user`)
715
- };
716
- };
717
- const gitlab = (options) => {
718
- const { authorizationEndpoint, tokenEndpoint, userinfoEndpoint } = issuerToEndpoints(options.issuer);
719
- const issuerId = "gitlab";
720
- return {
721
- id: issuerId,
722
- name: "Gitlab",
723
- createAuthorizationURL: async ({ state, scopes, codeVerifier, loginHint, redirectURI }) => {
724
- const _scopes = options.disableDefaultScope ? [] : ["read_user"];
725
- if (options.scope) _scopes.push(...options.scope);
726
- if (scopes) _scopes.push(...scopes);
727
- return await createAuthorizationURL({
728
- id: issuerId,
729
- options,
730
- authorizationEndpoint,
731
- scopes: _scopes,
732
- state,
733
- redirectURI,
734
- codeVerifier,
735
- loginHint
736
- });
737
- },
738
- validateAuthorizationCode: async ({ code, redirectURI, codeVerifier }) => {
739
- return validateAuthorizationCode({
740
- code,
741
- redirectURI,
742
- options,
743
- codeVerifier,
744
- tokenEndpoint
745
- });
746
- },
747
- refreshAccessToken: options.refreshAccessToken ? options.refreshAccessToken : async (refreshToken) => {
748
- return refreshAccessToken({
749
- refreshToken,
750
- options: {
751
- clientId: options.clientId,
752
- clientKey: options.clientKey,
753
- clientSecret: options.clientSecret
754
- },
755
- tokenEndpoint
756
- });
757
- },
758
- async getUserInfo(token) {
759
- if (options.getUserInfo) return options.getUserInfo(token);
760
- const { data: profile, error } = await betterFetch(userinfoEndpoint, { headers: { authorization: `Bearer ${token.accessToken}` } });
761
- if (error || profile.state !== "active" || profile.locked) return null;
762
- const userMap = await options.mapProfileToUser?.(profile);
763
- return {
764
- user: {
765
- id: profile.id,
766
- name: profile.name ?? profile.username,
767
- email: profile.email,
768
- image: profile.avatar_url,
769
- emailVerified: true,
770
- ...userMap
771
- },
772
- data: profile
773
- };
774
- },
775
- options
776
- };
777
- };
778
-
779
- //#endregion
780
- //#region src/social-providers/google.ts
781
- const google = (options) => {
782
- return {
783
- id: "google",
784
- name: "Google",
785
- async createAuthorizationURL({ state, scopes, codeVerifier, redirectURI, loginHint, display }) {
786
- if (!options.clientId || !options.clientSecret) {
787
- logger.error("Client Id and Client Secret is required for Google. Make sure to provide them in the options.");
788
- throw new PayvoAuthError("CLIENT_ID_AND_SECRET_REQUIRED");
789
- }
790
- if (!codeVerifier) throw new PayvoAuthError("codeVerifier is required for Google");
791
- const _scopes = options.disableDefaultScope ? [] : [
792
- "email",
793
- "profile",
794
- "openid"
795
- ];
796
- if (options.scope) _scopes.push(...options.scope);
797
- if (scopes) _scopes.push(...scopes);
798
- return await createAuthorizationURL({
799
- id: "google",
800
- options,
801
- authorizationEndpoint: "https://accounts.google.com/o/oauth2/auth",
802
- scopes: _scopes,
803
- state,
804
- codeVerifier,
805
- redirectURI,
806
- prompt: options.prompt,
807
- accessType: options.accessType,
808
- display: display || options.display,
809
- loginHint,
810
- hd: options.hd,
811
- additionalParams: { include_granted_scopes: "true" }
812
- });
813
- },
814
- validateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {
815
- return validateAuthorizationCode({
816
- code,
817
- codeVerifier,
818
- redirectURI,
819
- options,
820
- tokenEndpoint: "https://oauth2.googleapis.com/token"
821
- });
822
- },
823
- refreshAccessToken: options.refreshAccessToken ? options.refreshAccessToken : async (refreshToken) => {
824
- return refreshAccessToken({
825
- refreshToken,
826
- options: {
827
- clientId: options.clientId,
828
- clientKey: options.clientKey,
829
- clientSecret: options.clientSecret
830
- },
831
- tokenEndpoint: "https://www.googleapis.com/oauth2/v4/token"
832
- });
833
- },
834
- async verifyIdToken(token, nonce) {
835
- if (options.disableIdTokenSignIn) return false;
836
- if (options.verifyIdToken) return options.verifyIdToken(token, nonce);
837
- const { data: tokenInfo } = await betterFetch(`https://www.googleapis.com/oauth2/v3/tokeninfo?id_token=${token}`);
838
- if (!tokenInfo) return false;
839
- return tokenInfo.aud === options.clientId && (tokenInfo.iss === "https://accounts.google.com" || tokenInfo.iss === "accounts.google.com");
840
- },
841
- async getUserInfo(token) {
842
- if (options.getUserInfo) return options.getUserInfo(token);
843
- if (!token.idToken) return null;
844
- const user = decodeJwt(token.idToken);
845
- const userMap = await options.mapProfileToUser?.(user);
846
- return {
847
- user: {
848
- id: user.sub,
849
- name: user.name,
850
- email: user.email,
851
- image: user.picture,
852
- emailVerified: user.email_verified,
853
- ...userMap
854
- },
855
- data: user
856
- };
857
- },
858
- options
859
- };
860
- };
861
-
862
- //#endregion
863
- //#region src/social-providers/huggingface.ts
864
- const huggingface = (options) => {
865
- return {
866
- id: "huggingface",
867
- name: "Hugging Face",
868
- createAuthorizationURL({ state, scopes, codeVerifier, redirectURI }) {
869
- const _scopes = options.disableDefaultScope ? [] : [
870
- "openid",
871
- "profile",
872
- "email"
873
- ];
874
- if (options.scope) _scopes.push(...options.scope);
875
- if (scopes) _scopes.push(...scopes);
876
- return createAuthorizationURL({
877
- id: "huggingface",
878
- options,
879
- authorizationEndpoint: "https://huggingface.co/oauth/authorize",
880
- scopes: _scopes,
881
- state,
882
- codeVerifier,
883
- redirectURI
884
- });
885
- },
886
- validateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {
887
- return validateAuthorizationCode({
888
- code,
889
- codeVerifier,
890
- redirectURI,
891
- options,
892
- tokenEndpoint: "https://huggingface.co/oauth/token"
893
- });
894
- },
895
- refreshAccessToken: options.refreshAccessToken ? options.refreshAccessToken : async (refreshToken) => {
896
- return refreshAccessToken({
897
- refreshToken,
898
- options: {
899
- clientId: options.clientId,
900
- clientKey: options.clientKey,
901
- clientSecret: options.clientSecret
902
- },
903
- tokenEndpoint: "https://huggingface.co/oauth/token"
904
- });
905
- },
906
- async getUserInfo(token) {
907
- if (options.getUserInfo) return options.getUserInfo(token);
908
- const { data: profile, error } = await betterFetch("https://huggingface.co/oauth/userinfo", {
909
- method: "GET",
910
- headers: { Authorization: `Bearer ${token.accessToken}` }
911
- });
912
- if (error) return null;
913
- const userMap = await options.mapProfileToUser?.(profile);
914
- return {
915
- user: {
916
- id: profile.sub,
917
- name: profile.name || profile.preferred_username,
918
- email: profile.email,
919
- image: profile.picture,
920
- emailVerified: profile.email_verified ?? false,
921
- ...userMap
922
- },
923
- data: profile
924
- };
925
- },
926
- options
927
- };
928
- };
929
-
930
- //#endregion
931
- //#region src/social-providers/kakao.ts
932
- const kakao = (options) => {
933
- return {
934
- id: "kakao",
935
- name: "Kakao",
936
- createAuthorizationURL({ state, scopes, redirectURI }) {
937
- const _scopes = options.disableDefaultScope ? [] : [
938
- "account_email",
939
- "profile_image",
940
- "profile_nickname"
941
- ];
942
- if (options.scope) _scopes.push(...options.scope);
943
- if (scopes) _scopes.push(...scopes);
944
- return createAuthorizationURL({
945
- id: "kakao",
946
- options,
947
- authorizationEndpoint: "https://kauth.kakao.com/oauth/authorize",
948
- scopes: _scopes,
949
- state,
950
- redirectURI
951
- });
952
- },
953
- validateAuthorizationCode: async ({ code, redirectURI }) => {
954
- return validateAuthorizationCode({
955
- code,
956
- redirectURI,
957
- options,
958
- tokenEndpoint: "https://kauth.kakao.com/oauth/token"
959
- });
960
- },
961
- refreshAccessToken: options.refreshAccessToken ? options.refreshAccessToken : async (refreshToken) => {
962
- return refreshAccessToken({
963
- refreshToken,
964
- options: {
965
- clientId: options.clientId,
966
- clientKey: options.clientKey,
967
- clientSecret: options.clientSecret
968
- },
969
- tokenEndpoint: "https://kauth.kakao.com/oauth/token"
970
- });
971
- },
972
- async getUserInfo(token) {
973
- if (options.getUserInfo) return options.getUserInfo(token);
974
- const { data: profile, error } = await betterFetch("https://kapi.kakao.com/v2/user/me", { headers: { Authorization: `Bearer ${token.accessToken}` } });
975
- if (error || !profile) return null;
976
- const userMap = await options.mapProfileToUser?.(profile);
977
- const account = profile.kakao_account || {};
978
- const kakaoProfile = account.profile || {};
979
- return {
980
- user: {
981
- id: String(profile.id),
982
- name: kakaoProfile.nickname || account.name || void 0,
983
- email: account.email,
984
- image: kakaoProfile.profile_image_url || kakaoProfile.thumbnail_image_url,
985
- emailVerified: !!account.is_email_valid && !!account.is_email_verified,
986
- ...userMap
987
- },
988
- data: profile
989
- };
990
- },
991
- options
992
- };
993
- };
994
-
995
- //#endregion
996
- //#region src/social-providers/kick.ts
997
- const kick = (options) => {
998
- return {
999
- id: "kick",
1000
- name: "Kick",
1001
- createAuthorizationURL({ state, scopes, redirectURI, codeVerifier }) {
1002
- const _scopes = options.disableDefaultScope ? [] : ["user:read"];
1003
- if (options.scope) _scopes.push(...options.scope);
1004
- if (scopes) _scopes.push(...scopes);
1005
- return createAuthorizationURL({
1006
- id: "kick",
1007
- redirectURI,
1008
- options,
1009
- authorizationEndpoint: "https://id.kick.com/oauth/authorize",
1010
- scopes: _scopes,
1011
- codeVerifier,
1012
- state
1013
- });
1014
- },
1015
- async validateAuthorizationCode({ code, redirectURI, codeVerifier }) {
1016
- return validateAuthorizationCode({
1017
- code,
1018
- redirectURI,
1019
- options,
1020
- tokenEndpoint: "https://id.kick.com/oauth/token",
1021
- codeVerifier
1022
- });
1023
- },
1024
- async getUserInfo(token) {
1025
- if (options.getUserInfo) return options.getUserInfo(token);
1026
- const { data, error } = await betterFetch("https://api.kick.com/public/v1/users", {
1027
- method: "GET",
1028
- headers: { Authorization: `Bearer ${token.accessToken}` }
1029
- });
1030
- if (error) return null;
1031
- const profile = data.data[0];
1032
- const userMap = await options.mapProfileToUser?.(profile);
1033
- return {
1034
- user: {
1035
- id: profile.user_id,
1036
- name: profile.name,
1037
- email: profile.email,
1038
- image: profile.profile_picture,
1039
- emailVerified: true,
1040
- ...userMap
1041
- },
1042
- data: profile
1043
- };
1044
- },
1045
- options
1046
- };
1047
- };
1048
-
1049
- //#endregion
1050
- //#region src/social-providers/line.ts
1051
- /**
1052
- * LINE Login v2.1
1053
- * - Authorization endpoint: https://access.line.me/oauth2/v2.1/authorize
1054
- * - Token endpoint: https://api.line.me/oauth2/v2.1/token
1055
- * - UserInfo endpoint: https://api.line.me/oauth2/v2.1/userinfo
1056
- * - Verify ID token: https://api.line.me/oauth2/v2.1/verify
1057
- *
1058
- * Docs: https://developers.line.biz/en/reference/line-login/#issue-access-token
1059
- */
1060
- const line = (options) => {
1061
- const authorizationEndpoint = "https://access.line.me/oauth2/v2.1/authorize";
1062
- const tokenEndpoint = "https://api.line.me/oauth2/v2.1/token";
1063
- const userInfoEndpoint = "https://api.line.me/oauth2/v2.1/userinfo";
1064
- const verifyIdTokenEndpoint = "https://api.line.me/oauth2/v2.1/verify";
1065
- return {
1066
- id: "line",
1067
- name: "LINE",
1068
- async createAuthorizationURL({ state, scopes, codeVerifier, redirectURI, loginHint }) {
1069
- const _scopes = options.disableDefaultScope ? [] : [
1070
- "openid",
1071
- "profile",
1072
- "email"
1073
- ];
1074
- if (options.scope) _scopes.push(...options.scope);
1075
- if (scopes) _scopes.push(...scopes);
1076
- return await createAuthorizationURL({
1077
- id: "line",
1078
- options,
1079
- authorizationEndpoint,
1080
- scopes: _scopes,
1081
- state,
1082
- codeVerifier,
1083
- redirectURI,
1084
- loginHint
1085
- });
1086
- },
1087
- validateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {
1088
- return validateAuthorizationCode({
1089
- code,
1090
- codeVerifier,
1091
- redirectURI,
1092
- options,
1093
- tokenEndpoint
1094
- });
1095
- },
1096
- refreshAccessToken: options.refreshAccessToken ? options.refreshAccessToken : async (refreshToken) => {
1097
- return refreshAccessToken({
1098
- refreshToken,
1099
- options: {
1100
- clientId: options.clientId,
1101
- clientSecret: options.clientSecret
1102
- },
1103
- tokenEndpoint
1104
- });
1105
- },
1106
- async verifyIdToken(token, nonce) {
1107
- if (options.disableIdTokenSignIn) return false;
1108
- if (options.verifyIdToken) return options.verifyIdToken(token, nonce);
1109
- const body = new URLSearchParams();
1110
- body.set("id_token", token);
1111
- body.set("client_id", options.clientId);
1112
- if (nonce) body.set("nonce", nonce);
1113
- const { data, error } = await betterFetch(verifyIdTokenEndpoint, {
1114
- method: "POST",
1115
- headers: { "content-type": "application/x-www-form-urlencoded" },
1116
- body
1117
- });
1118
- if (error || !data) return false;
1119
- if (data.aud !== options.clientId) return false;
1120
- if (nonce && data.nonce && data.nonce !== nonce) return false;
1121
- return true;
1122
- },
1123
- async getUserInfo(token) {
1124
- if (options.getUserInfo) return options.getUserInfo(token);
1125
- let profile = null;
1126
- if (token.idToken) try {
1127
- profile = decodeJwt(token.idToken);
1128
- } catch {}
1129
- if (!profile) {
1130
- const { data } = await betterFetch(userInfoEndpoint, { headers: { authorization: `Bearer ${token.accessToken}` } });
1131
- profile = data || null;
1132
- }
1133
- if (!profile) return null;
1134
- const userMap = await options.mapProfileToUser?.(profile);
1135
- const id = profile.sub || profile.userId;
1136
- const name = profile.name || profile.displayName;
1137
- const image = profile.picture || profile.pictureUrl || void 0;
1138
- return {
1139
- user: {
1140
- id,
1141
- name,
1142
- email: profile.email,
1143
- image,
1144
- emailVerified: false,
1145
- ...userMap
1146
- },
1147
- data: profile
1148
- };
1149
- },
1150
- options
1151
- };
1152
- };
1153
-
1154
- //#endregion
1155
- //#region src/social-providers/linear.ts
1156
- const linear = (options) => {
1157
- const tokenEndpoint = "https://api.linear.app/oauth/token";
1158
- return {
1159
- id: "linear",
1160
- name: "Linear",
1161
- createAuthorizationURL({ state, scopes, loginHint, redirectURI }) {
1162
- const _scopes = options.disableDefaultScope ? [] : ["read"];
1163
- if (options.scope) _scopes.push(...options.scope);
1164
- if (scopes) _scopes.push(...scopes);
1165
- return createAuthorizationURL({
1166
- id: "linear",
1167
- options,
1168
- authorizationEndpoint: "https://linear.app/oauth/authorize",
1169
- scopes: _scopes,
1170
- state,
1171
- redirectURI,
1172
- loginHint
1173
- });
1174
- },
1175
- validateAuthorizationCode: async ({ code, redirectURI }) => {
1176
- return validateAuthorizationCode({
1177
- code,
1178
- redirectURI,
1179
- options,
1180
- tokenEndpoint
1181
- });
1182
- },
1183
- refreshAccessToken: options.refreshAccessToken ? options.refreshAccessToken : async (refreshToken) => {
1184
- return refreshAccessToken({
1185
- refreshToken,
1186
- options: {
1187
- clientId: options.clientId,
1188
- clientKey: options.clientKey,
1189
- clientSecret: options.clientSecret
1190
- },
1191
- tokenEndpoint
1192
- });
1193
- },
1194
- async getUserInfo(token) {
1195
- if (options.getUserInfo) return options.getUserInfo(token);
1196
- const { data: profile, error } = await betterFetch("https://api.linear.app/graphql", {
1197
- method: "POST",
1198
- headers: {
1199
- "Content-Type": "application/json",
1200
- Authorization: `Bearer ${token.accessToken}`
1201
- },
1202
- body: JSON.stringify({ query: `
1203
- query {
1204
- viewer {
1205
- id
1206
- name
1207
- email
1208
- avatarUrl
1209
- active
1210
- createdAt
1211
- updatedAt
1212
- }
1213
- }
1214
- ` })
1215
- });
1216
- if (error || !profile?.data?.viewer) return null;
1217
- const userData = profile.data.viewer;
1218
- const userMap = await options.mapProfileToUser?.(userData);
1219
- return {
1220
- user: {
1221
- id: profile.data.viewer.id,
1222
- name: profile.data.viewer.name,
1223
- email: profile.data.viewer.email,
1224
- image: profile.data.viewer.avatarUrl,
1225
- emailVerified: true,
1226
- ...userMap
1227
- },
1228
- data: userData
1229
- };
1230
- },
1231
- options
1232
- };
1233
- };
1234
-
1235
- //#endregion
1236
- //#region src/social-providers/linkedin.ts
1237
- const linkedin = (options) => {
1238
- const authorizationEndpoint = "https://www.linkedin.com/oauth/v2/authorization";
1239
- const tokenEndpoint = "https://www.linkedin.com/oauth/v2/accessToken";
1240
- return {
1241
- id: "linkedin",
1242
- name: "Linkedin",
1243
- createAuthorizationURL: async ({ state, scopes, redirectURI, loginHint }) => {
1244
- const _scopes = options.disableDefaultScope ? [] : [
1245
- "profile",
1246
- "email",
1247
- "openid"
1248
- ];
1249
- if (options.scope) _scopes.push(...options.scope);
1250
- if (scopes) _scopes.push(...scopes);
1251
- return await createAuthorizationURL({
1252
- id: "linkedin",
1253
- options,
1254
- authorizationEndpoint,
1255
- scopes: _scopes,
1256
- state,
1257
- loginHint,
1258
- redirectURI
1259
- });
1260
- },
1261
- validateAuthorizationCode: async ({ code, redirectURI }) => {
1262
- return await validateAuthorizationCode({
1263
- code,
1264
- redirectURI,
1265
- options,
1266
- tokenEndpoint
1267
- });
1268
- },
1269
- refreshAccessToken: options.refreshAccessToken ? options.refreshAccessToken : async (refreshToken) => {
1270
- return refreshAccessToken({
1271
- refreshToken,
1272
- options: {
1273
- clientId: options.clientId,
1274
- clientKey: options.clientKey,
1275
- clientSecret: options.clientSecret
1276
- },
1277
- tokenEndpoint
1278
- });
1279
- },
1280
- async getUserInfo(token) {
1281
- if (options.getUserInfo) return options.getUserInfo(token);
1282
- const { data: profile, error } = await betterFetch("https://api.linkedin.com/v2/userinfo", {
1283
- method: "GET",
1284
- headers: { Authorization: `Bearer ${token.accessToken}` }
1285
- });
1286
- if (error) return null;
1287
- const userMap = await options.mapProfileToUser?.(profile);
1288
- return {
1289
- user: {
1290
- id: profile.sub,
1291
- name: profile.name,
1292
- email: profile.email,
1293
- emailVerified: profile.email_verified || false,
1294
- image: profile.picture,
1295
- ...userMap
1296
- },
1297
- data: profile
1298
- };
1299
- },
1300
- options
1301
- };
1302
- };
1303
-
1304
- //#endregion
1305
- //#region src/social-providers/microsoft-entra-id.ts
1306
- const microsoft = (options) => {
1307
- const tenant = options.tenantId || "common";
1308
- const authority = options.authority || "https://login.microsoftonline.com";
1309
- const authorizationEndpoint = `${authority}/${tenant}/oauth2/v2.0/authorize`;
1310
- const tokenEndpoint = `${authority}/${tenant}/oauth2/v2.0/token`;
1311
- return {
1312
- id: "microsoft",
1313
- name: "Microsoft EntraID",
1314
- createAuthorizationURL(data) {
1315
- const scopes = options.disableDefaultScope ? [] : [
1316
- "openid",
1317
- "profile",
1318
- "email",
1319
- "User.Read",
1320
- "offline_access"
1321
- ];
1322
- if (options.scope) scopes.push(...options.scope);
1323
- if (data.scopes) scopes.push(...data.scopes);
1324
- return createAuthorizationURL({
1325
- id: "microsoft",
1326
- options,
1327
- authorizationEndpoint,
1328
- state: data.state,
1329
- codeVerifier: data.codeVerifier,
1330
- scopes,
1331
- redirectURI: data.redirectURI,
1332
- prompt: options.prompt,
1333
- loginHint: data.loginHint
1334
- });
1335
- },
1336
- validateAuthorizationCode({ code, codeVerifier, redirectURI }) {
1337
- return validateAuthorizationCode({
1338
- code,
1339
- codeVerifier,
1340
- redirectURI,
1341
- options,
1342
- tokenEndpoint
1343
- });
1344
- },
1345
- async getUserInfo(token) {
1346
- if (options.getUserInfo) return options.getUserInfo(token);
1347
- if (!token.idToken) return null;
1348
- const user = decodeJwt(token.idToken);
1349
- const profilePhotoSize = options.profilePhotoSize || 48;
1350
- await betterFetch(`https://graph.microsoft.com/v1.0/me/photos/${profilePhotoSize}x${profilePhotoSize}/$value`, {
1351
- headers: { Authorization: `Bearer ${token.accessToken}` },
1352
- async onResponse(context) {
1353
- if (options.disableProfilePhoto || !context.response.ok) return;
1354
- try {
1355
- const pictureBuffer = await context.response.clone().arrayBuffer();
1356
- user.picture = `data:image/jpeg;base64, ${base64.encode(pictureBuffer)}`;
1357
- } catch (e) {
1358
- logger.error(e && typeof e === "object" && "name" in e ? e.name : "", e);
1359
- }
1360
- }
1361
- });
1362
- const userMap = await options.mapProfileToUser?.(user);
1363
- return {
1364
- user: {
1365
- id: user.sub,
1366
- name: user.name,
1367
- email: user.email,
1368
- image: user.picture,
1369
- emailVerified: true,
1370
- ...userMap
1371
- },
1372
- data: user
1373
- };
1374
- },
1375
- refreshAccessToken: options.refreshAccessToken ? options.refreshAccessToken : async (refreshToken) => {
1376
- const scopes = options.disableDefaultScope ? [] : [
1377
- "openid",
1378
- "profile",
1379
- "email",
1380
- "User.Read",
1381
- "offline_access"
1382
- ];
1383
- if (options.scope) scopes.push(...options.scope);
1384
- return refreshAccessToken({
1385
- refreshToken,
1386
- options: {
1387
- clientId: options.clientId,
1388
- clientSecret: options.clientSecret
1389
- },
1390
- extraParams: { scope: scopes.join(" ") },
1391
- tokenEndpoint
1392
- });
1393
- },
1394
- options
1395
- };
1396
- };
1397
-
1398
- //#endregion
1399
- //#region src/social-providers/naver.ts
1400
- const naver = (options) => {
1401
- return {
1402
- id: "naver",
1403
- name: "Naver",
1404
- createAuthorizationURL({ state, scopes, redirectURI }) {
1405
- const _scopes = options.disableDefaultScope ? [] : ["profile", "email"];
1406
- if (options.scope) _scopes.push(...options.scope);
1407
- if (scopes) _scopes.push(...scopes);
1408
- return createAuthorizationURL({
1409
- id: "naver",
1410
- options,
1411
- authorizationEndpoint: "https://nid.naver.com/oauth2.0/authorize",
1412
- scopes: _scopes,
1413
- state,
1414
- redirectURI
1415
- });
1416
- },
1417
- validateAuthorizationCode: async ({ code, redirectURI }) => {
1418
- return validateAuthorizationCode({
1419
- code,
1420
- redirectURI,
1421
- options,
1422
- tokenEndpoint: "https://nid.naver.com/oauth2.0/token"
1423
- });
1424
- },
1425
- refreshAccessToken: options.refreshAccessToken ? options.refreshAccessToken : async (refreshToken) => {
1426
- return refreshAccessToken({
1427
- refreshToken,
1428
- options: {
1429
- clientId: options.clientId,
1430
- clientKey: options.clientKey,
1431
- clientSecret: options.clientSecret
1432
- },
1433
- tokenEndpoint: "https://nid.naver.com/oauth2.0/token"
1434
- });
1435
- },
1436
- async getUserInfo(token) {
1437
- if (options.getUserInfo) return options.getUserInfo(token);
1438
- const { data: profile, error } = await betterFetch("https://openapi.naver.com/v1/nid/me", { headers: { Authorization: `Bearer ${token.accessToken}` } });
1439
- if (error || !profile || profile.resultcode !== "00") return null;
1440
- const userMap = await options.mapProfileToUser?.(profile);
1441
- const res = profile.response || {};
1442
- return {
1443
- user: {
1444
- id: res.id,
1445
- name: res.name || res.nickname,
1446
- email: res.email,
1447
- image: res.profile_image,
1448
- emailVerified: false,
1449
- ...userMap
1450
- },
1451
- data: profile
1452
- };
1453
- },
1454
- options
1455
- };
1456
- };
1457
-
1458
- //#endregion
1459
- //#region src/social-providers/notion.ts
1460
- const notion = (options) => {
1461
- const tokenEndpoint = "https://api.notion.com/v1/oauth/token";
1462
- return {
1463
- id: "notion",
1464
- name: "Notion",
1465
- createAuthorizationURL({ state, scopes, loginHint, redirectURI }) {
1466
- const _scopes = options.disableDefaultScope ? [] : [];
1467
- if (options.scope) _scopes.push(...options.scope);
1468
- if (scopes) _scopes.push(...scopes);
1469
- return createAuthorizationURL({
1470
- id: "notion",
1471
- options,
1472
- authorizationEndpoint: "https://api.notion.com/v1/oauth/authorize",
1473
- scopes: _scopes,
1474
- state,
1475
- redirectURI,
1476
- loginHint,
1477
- additionalParams: { owner: "user" }
1478
- });
1479
- },
1480
- validateAuthorizationCode: async ({ code, redirectURI }) => {
1481
- return validateAuthorizationCode({
1482
- code,
1483
- redirectURI,
1484
- options,
1485
- tokenEndpoint,
1486
- authentication: "basic"
1487
- });
1488
- },
1489
- refreshAccessToken: options.refreshAccessToken ? options.refreshAccessToken : async (refreshToken) => {
1490
- return refreshAccessToken({
1491
- refreshToken,
1492
- options: {
1493
- clientId: options.clientId,
1494
- clientKey: options.clientKey,
1495
- clientSecret: options.clientSecret
1496
- },
1497
- tokenEndpoint
1498
- });
1499
- },
1500
- async getUserInfo(token) {
1501
- if (options.getUserInfo) return options.getUserInfo(token);
1502
- const { data: profile, error } = await betterFetch("https://api.notion.com/v1/users/me", { headers: {
1503
- Authorization: `Bearer ${token.accessToken}`,
1504
- "Notion-Version": "2022-06-28"
1505
- } });
1506
- if (error || !profile) return null;
1507
- const userProfile = profile.bot?.owner?.user;
1508
- if (!userProfile) return null;
1509
- const userMap = await options.mapProfileToUser?.(userProfile);
1510
- return {
1511
- user: {
1512
- id: userProfile.id,
1513
- name: userProfile.name || "Notion User",
1514
- email: userProfile.person?.email || null,
1515
- image: userProfile.avatar_url,
1516
- emailVerified: !!userProfile.person?.email,
1517
- ...userMap
1518
- },
1519
- data: userProfile
1520
- };
1521
- },
1522
- options
1523
- };
1524
- };
1525
-
1526
- //#endregion
1527
- //#region src/social-providers/paybin.ts
1528
- const paybin = (options) => {
1529
- const issuer = options.issuer || "https://idp.paybin.io";
1530
- const authorizationEndpoint = `${issuer}/oauth2/authorize`;
1531
- const tokenEndpoint = `${issuer}/oauth2/token`;
1532
- return {
1533
- id: "paybin",
1534
- name: "Paybin",
1535
- async createAuthorizationURL({ state, scopes, codeVerifier, redirectURI, loginHint }) {
1536
- if (!options.clientId || !options.clientSecret) {
1537
- logger.error("Client Id and Client Secret is required for Paybin. Make sure to provide them in the options.");
1538
- throw new PayvoAuthError("CLIENT_ID_AND_SECRET_REQUIRED");
1539
- }
1540
- if (!codeVerifier) throw new PayvoAuthError("codeVerifier is required for Paybin");
1541
- const _scopes = options.disableDefaultScope ? [] : [
1542
- "openid",
1543
- "email",
1544
- "profile"
1545
- ];
1546
- if (options.scope) _scopes.push(...options.scope);
1547
- if (scopes) _scopes.push(...scopes);
1548
- return await createAuthorizationURL({
1549
- id: "paybin",
1550
- options,
1551
- authorizationEndpoint,
1552
- scopes: _scopes,
1553
- state,
1554
- codeVerifier,
1555
- redirectURI,
1556
- prompt: options.prompt,
1557
- loginHint
1558
- });
1559
- },
1560
- validateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {
1561
- return validateAuthorizationCode({
1562
- code,
1563
- codeVerifier,
1564
- redirectURI,
1565
- options,
1566
- tokenEndpoint
1567
- });
1568
- },
1569
- refreshAccessToken: options.refreshAccessToken ? options.refreshAccessToken : async (refreshToken) => {
1570
- return refreshAccessToken({
1571
- refreshToken,
1572
- options: {
1573
- clientId: options.clientId,
1574
- clientKey: options.clientKey,
1575
- clientSecret: options.clientSecret
1576
- },
1577
- tokenEndpoint
1578
- });
1579
- },
1580
- async getUserInfo(token) {
1581
- if (options.getUserInfo) return options.getUserInfo(token);
1582
- if (!token.idToken) return null;
1583
- const user = decodeJwt(token.idToken);
1584
- const userMap = await options.mapProfileToUser?.(user);
1585
- return {
1586
- user: {
1587
- id: user.sub,
1588
- name: user.name || user.preferred_username || (user.email ? user.email.split("@")[0] : "User") || "User",
1589
- email: user.email,
1590
- image: user.picture,
1591
- emailVerified: user.email_verified || false,
1592
- ...userMap
1593
- },
1594
- data: user
1595
- };
1596
- },
1597
- options
1598
- };
1599
- };
1600
-
1601
- //#endregion
1602
- //#region src/social-providers/paypal.ts
1603
- const paypal = (options) => {
1604
- const isSandbox = (options.environment || "sandbox") === "sandbox";
1605
- const authorizationEndpoint = isSandbox ? "https://www.sandbox.paypal.com/signin/authorize" : "https://www.paypal.com/signin/authorize";
1606
- const tokenEndpoint = isSandbox ? "https://api-m.sandbox.paypal.com/v1/oauth2/token" : "https://api-m.paypal.com/v1/oauth2/token";
1607
- const userInfoEndpoint = isSandbox ? "https://api-m.sandbox.paypal.com/v1/identity/oauth2/userinfo" : "https://api-m.paypal.com/v1/identity/oauth2/userinfo";
1608
- return {
1609
- id: "paypal",
1610
- name: "PayPal",
1611
- async createAuthorizationURL({ state, codeVerifier, redirectURI }) {
1612
- if (!options.clientId || !options.clientSecret) {
1613
- logger.error("Client Id and Client Secret is required for PayPal. Make sure to provide them in the options.");
1614
- throw new PayvoAuthError("CLIENT_ID_AND_SECRET_REQUIRED");
1615
- }
1616
- return await createAuthorizationURL({
1617
- id: "paypal",
1618
- options,
1619
- authorizationEndpoint,
1620
- scopes: [],
1621
- state,
1622
- codeVerifier,
1623
- redirectURI,
1624
- prompt: options.prompt
1625
- });
1626
- },
1627
- validateAuthorizationCode: async ({ code, redirectURI }) => {
1628
- /**
1629
- * PayPal requires Basic Auth for token exchange
1630
- **/
1631
- const credentials = base64.encode(`${options.clientId}:${options.clientSecret}`);
1632
- try {
1633
- const response = await betterFetch(tokenEndpoint, {
1634
- method: "POST",
1635
- headers: {
1636
- Authorization: `Basic ${credentials}`,
1637
- Accept: "application/json",
1638
- "Accept-Language": "en_US",
1639
- "Content-Type": "application/x-www-form-urlencoded"
1640
- },
1641
- body: new URLSearchParams({
1642
- grant_type: "authorization_code",
1643
- code,
1644
- redirect_uri: redirectURI
1645
- }).toString()
1646
- });
1647
- if (!response.data) throw new PayvoAuthError("FAILED_TO_GET_ACCESS_TOKEN");
1648
- const data = response.data;
1649
- return {
1650
- accessToken: data.access_token,
1651
- refreshToken: data.refresh_token,
1652
- accessTokenExpiresAt: data.expires_in ? new Date(Date.now() + data.expires_in * 1e3) : void 0,
1653
- idToken: data.id_token
1654
- };
1655
- } catch (error) {
1656
- logger.error("PayPal token exchange failed:", error);
1657
- throw new PayvoAuthError("FAILED_TO_GET_ACCESS_TOKEN");
1658
- }
1659
- },
1660
- refreshAccessToken: options.refreshAccessToken ? options.refreshAccessToken : async (refreshToken) => {
1661
- const credentials = base64.encode(`${options.clientId}:${options.clientSecret}`);
1662
- try {
1663
- const response = await betterFetch(tokenEndpoint, {
1664
- method: "POST",
1665
- headers: {
1666
- Authorization: `Basic ${credentials}`,
1667
- Accept: "application/json",
1668
- "Accept-Language": "en_US",
1669
- "Content-Type": "application/x-www-form-urlencoded"
1670
- },
1671
- body: new URLSearchParams({
1672
- grant_type: "refresh_token",
1673
- refresh_token: refreshToken
1674
- }).toString()
1675
- });
1676
- if (!response.data) throw new PayvoAuthError("FAILED_TO_REFRESH_ACCESS_TOKEN");
1677
- const data = response.data;
1678
- return {
1679
- accessToken: data.access_token,
1680
- refreshToken: data.refresh_token,
1681
- accessTokenExpiresAt: data.expires_in ? new Date(Date.now() + data.expires_in * 1e3) : void 0
1682
- };
1683
- } catch (error) {
1684
- logger.error("PayPal token refresh failed:", error);
1685
- throw new PayvoAuthError("FAILED_TO_REFRESH_ACCESS_TOKEN");
1686
- }
1687
- },
1688
- async verifyIdToken(token, nonce) {
1689
- if (options.disableIdTokenSignIn) return false;
1690
- if (options.verifyIdToken) return options.verifyIdToken(token, nonce);
1691
- try {
1692
- return !!decodeJwt(token).sub;
1693
- } catch (error) {
1694
- logger.error("Failed to verify PayPal ID token:", error);
1695
- return false;
1696
- }
1697
- },
1698
- async getUserInfo(token) {
1699
- if (options.getUserInfo) return options.getUserInfo(token);
1700
- if (!token.accessToken) {
1701
- logger.error("Access token is required to fetch PayPal user info");
1702
- return null;
1703
- }
1704
- try {
1705
- const response = await betterFetch(`${userInfoEndpoint}?schema=paypalv1.1`, { headers: {
1706
- Authorization: `Bearer ${token.accessToken}`,
1707
- Accept: "application/json"
1708
- } });
1709
- if (!response.data) {
1710
- logger.error("Failed to fetch user info from PayPal");
1711
- return null;
1712
- }
1713
- const userInfo = response.data;
1714
- const userMap = await options.mapProfileToUser?.(userInfo);
1715
- return {
1716
- user: {
1717
- id: userInfo.user_id,
1718
- name: userInfo.name,
1719
- email: userInfo.email,
1720
- image: userInfo.picture,
1721
- emailVerified: userInfo.email_verified,
1722
- ...userMap
1723
- },
1724
- data: userInfo
1725
- };
1726
- } catch (error) {
1727
- logger.error("Failed to fetch user info from PayPal:", error);
1728
- return null;
1729
- }
1730
- },
1731
- options
1732
- };
1733
- };
1734
-
1735
- //#endregion
1736
- //#region src/social-providers/polar.ts
1737
- const polar = (options) => {
1738
- return {
1739
- id: "polar",
1740
- name: "Polar",
1741
- createAuthorizationURL({ state, scopes, codeVerifier, redirectURI }) {
1742
- const _scopes = options.disableDefaultScope ? [] : [
1743
- "openid",
1744
- "profile",
1745
- "email"
1746
- ];
1747
- if (options.scope) _scopes.push(...options.scope);
1748
- if (scopes) _scopes.push(...scopes);
1749
- return createAuthorizationURL({
1750
- id: "polar",
1751
- options,
1752
- authorizationEndpoint: "https://polar.sh/oauth2/authorize",
1753
- scopes: _scopes,
1754
- state,
1755
- codeVerifier,
1756
- redirectURI,
1757
- prompt: options.prompt
1758
- });
1759
- },
1760
- validateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {
1761
- return validateAuthorizationCode({
1762
- code,
1763
- codeVerifier,
1764
- redirectURI,
1765
- options,
1766
- tokenEndpoint: "https://api.polar.sh/v1/oauth2/token"
1767
- });
1768
- },
1769
- refreshAccessToken: options.refreshAccessToken ? options.refreshAccessToken : async (refreshToken) => {
1770
- return refreshAccessToken({
1771
- refreshToken,
1772
- options: {
1773
- clientId: options.clientId,
1774
- clientKey: options.clientKey,
1775
- clientSecret: options.clientSecret
1776
- },
1777
- tokenEndpoint: "https://api.polar.sh/v1/oauth2/token"
1778
- });
1779
- },
1780
- async getUserInfo(token) {
1781
- if (options.getUserInfo) return options.getUserInfo(token);
1782
- const { data: profile, error } = await betterFetch("https://api.polar.sh/v1/oauth2/userinfo", { headers: { Authorization: `Bearer ${token.accessToken}` } });
1783
- if (error) return null;
1784
- const userMap = await options.mapProfileToUser?.(profile);
1785
- return {
1786
- user: {
1787
- id: profile.id,
1788
- name: profile.public_name || profile.username,
1789
- email: profile.email,
1790
- image: profile.avatar_url,
1791
- emailVerified: true,
1792
- ...userMap
1793
- },
1794
- data: profile
1795
- };
1796
- },
1797
- options
1798
- };
1799
- };
1800
-
1801
- //#endregion
1802
- //#region src/social-providers/reddit.ts
1803
- const reddit = (options) => {
1804
- return {
1805
- id: "reddit",
1806
- name: "Reddit",
1807
- createAuthorizationURL({ state, scopes, redirectURI }) {
1808
- const _scopes = options.disableDefaultScope ? [] : ["identity"];
1809
- if (options.scope) _scopes.push(...options.scope);
1810
- if (scopes) _scopes.push(...scopes);
1811
- return createAuthorizationURL({
1812
- id: "reddit",
1813
- options,
1814
- authorizationEndpoint: "https://www.reddit.com/api/v1/authorize",
1815
- scopes: _scopes,
1816
- state,
1817
- redirectURI,
1818
- duration: options.duration
1819
- });
1820
- },
1821
- validateAuthorizationCode: async ({ code, redirectURI }) => {
1822
- const body = new URLSearchParams({
1823
- grant_type: "authorization_code",
1824
- code,
1825
- redirect_uri: options.redirectURI || redirectURI
1826
- });
1827
- const { data, error } = await betterFetch("https://www.reddit.com/api/v1/access_token", {
1828
- method: "POST",
1829
- headers: {
1830
- "content-type": "application/x-www-form-urlencoded",
1831
- accept: "text/plain",
1832
- "user-agent": "gatwech",
1833
- Authorization: `Basic ${base64.encode(`${options.clientId}:${options.clientSecret}`)}`
1834
- },
1835
- body: body.toString()
1836
- });
1837
- if (error) throw error;
1838
- return getOAuth2Tokens(data);
1839
- },
1840
- refreshAccessToken: options.refreshAccessToken ? options.refreshAccessToken : async (refreshToken) => {
1841
- return refreshAccessToken({
1842
- refreshToken,
1843
- options: {
1844
- clientId: options.clientId,
1845
- clientKey: options.clientKey,
1846
- clientSecret: options.clientSecret
1847
- },
1848
- authentication: "basic",
1849
- tokenEndpoint: "https://www.reddit.com/api/v1/access_token"
1850
- });
1851
- },
1852
- async getUserInfo(token) {
1853
- if (options.getUserInfo) return options.getUserInfo(token);
1854
- const { data: profile, error } = await betterFetch("https://oauth.reddit.com/api/v1/me", { headers: {
1855
- Authorization: `Bearer ${token.accessToken}`,
1856
- "User-Agent": "gatwech"
1857
- } });
1858
- if (error) return null;
1859
- const userMap = await options.mapProfileToUser?.(profile);
1860
- return {
1861
- user: {
1862
- id: profile.id,
1863
- name: profile.name,
1864
- email: profile.oauth_client_id,
1865
- emailVerified: profile.has_verified_email,
1866
- image: profile.icon_img?.split("?")[0],
1867
- ...userMap
1868
- },
1869
- data: profile
1870
- };
1871
- },
1872
- options
1873
- };
1874
- };
1875
-
1876
- //#endregion
1877
- //#region src/social-providers/roblox.ts
1878
- const roblox = (options) => {
1879
- return {
1880
- id: "roblox",
1881
- name: "Roblox",
1882
- createAuthorizationURL({ state, scopes, redirectURI }) {
1883
- const _scopes = options.disableDefaultScope ? [] : ["openid", "profile"];
1884
- if (options.scope) _scopes.push(...options.scope);
1885
- if (scopes) _scopes.push(...scopes);
1886
- return new URL(`https://apis.roblox.com/oauth/v1/authorize?scope=${_scopes.join("+")}&response_type=code&client_id=${options.clientId}&redirect_uri=${encodeURIComponent(options.redirectURI || redirectURI)}&state=${state}&prompt=${options.prompt || "select_account consent"}`);
1887
- },
1888
- validateAuthorizationCode: async ({ code, redirectURI }) => {
1889
- return validateAuthorizationCode({
1890
- code,
1891
- redirectURI: options.redirectURI || redirectURI,
1892
- options,
1893
- tokenEndpoint: "https://apis.roblox.com/oauth/v1/token",
1894
- authentication: "post"
1895
- });
1896
- },
1897
- refreshAccessToken: options.refreshAccessToken ? options.refreshAccessToken : async (refreshToken) => {
1898
- return refreshAccessToken({
1899
- refreshToken,
1900
- options: {
1901
- clientId: options.clientId,
1902
- clientKey: options.clientKey,
1903
- clientSecret: options.clientSecret
1904
- },
1905
- tokenEndpoint: "https://apis.roblox.com/oauth/v1/token"
1906
- });
1907
- },
1908
- async getUserInfo(token) {
1909
- if (options.getUserInfo) return options.getUserInfo(token);
1910
- const { data: profile, error } = await betterFetch("https://apis.roblox.com/oauth/v1/userinfo", { headers: { authorization: `Bearer ${token.accessToken}` } });
1911
- if (error) return null;
1912
- const userMap = await options.mapProfileToUser?.(profile);
1913
- return {
1914
- user: {
1915
- id: profile.sub,
1916
- name: profile.nickname || profile.preferred_username || "",
1917
- image: profile.picture,
1918
- email: profile.preferred_username || null,
1919
- emailVerified: true,
1920
- ...userMap
1921
- },
1922
- data: { ...profile }
1923
- };
1924
- },
1925
- options
1926
- };
1927
- };
1928
-
1929
- //#endregion
1930
- //#region src/social-providers/salesforce.ts
1931
- const salesforce = (options) => {
1932
- const isSandbox = (options.environment ?? "production") === "sandbox";
1933
- const authorizationEndpoint = options.loginUrl ? `https://${options.loginUrl}/services/oauth2/authorize` : isSandbox ? "https://test.salesforce.com/services/oauth2/authorize" : "https://login.salesforce.com/services/oauth2/authorize";
1934
- const tokenEndpoint = options.loginUrl ? `https://${options.loginUrl}/services/oauth2/token` : isSandbox ? "https://test.salesforce.com/services/oauth2/token" : "https://login.salesforce.com/services/oauth2/token";
1935
- const userInfoEndpoint = options.loginUrl ? `https://${options.loginUrl}/services/oauth2/userinfo` : isSandbox ? "https://test.salesforce.com/services/oauth2/userinfo" : "https://login.salesforce.com/services/oauth2/userinfo";
1936
- return {
1937
- id: "salesforce",
1938
- name: "Salesforce",
1939
- async createAuthorizationURL({ state, scopes, codeVerifier, redirectURI }) {
1940
- if (!options.clientId || !options.clientSecret) {
1941
- logger.error("Client Id and Client Secret are required for Salesforce. Make sure to provide them in the options.");
1942
- throw new PayvoAuthError("CLIENT_ID_AND_SECRET_REQUIRED");
1943
- }
1944
- if (!codeVerifier) throw new PayvoAuthError("codeVerifier is required for Salesforce");
1945
- const _scopes = options.disableDefaultScope ? [] : [
1946
- "openid",
1947
- "email",
1948
- "profile"
1949
- ];
1950
- if (options.scope) _scopes.push(...options.scope);
1951
- if (scopes) _scopes.push(...scopes);
1952
- return createAuthorizationURL({
1953
- id: "salesforce",
1954
- options,
1955
- authorizationEndpoint,
1956
- scopes: _scopes,
1957
- state,
1958
- codeVerifier,
1959
- redirectURI: options.redirectURI || redirectURI
1960
- });
1961
- },
1962
- validateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {
1963
- return validateAuthorizationCode({
1964
- code,
1965
- codeVerifier,
1966
- redirectURI: options.redirectURI || redirectURI,
1967
- options,
1968
- tokenEndpoint
1969
- });
1970
- },
1971
- refreshAccessToken: options.refreshAccessToken ? options.refreshAccessToken : async (refreshToken) => {
1972
- return refreshAccessToken({
1973
- refreshToken,
1974
- options: {
1975
- clientId: options.clientId,
1976
- clientSecret: options.clientSecret
1977
- },
1978
- tokenEndpoint
1979
- });
1980
- },
1981
- async getUserInfo(token) {
1982
- if (options.getUserInfo) return options.getUserInfo(token);
1983
- try {
1984
- const { data: user } = await betterFetch(userInfoEndpoint, { headers: { Authorization: `Bearer ${token.accessToken}` } });
1985
- if (!user) {
1986
- logger.error("Failed to fetch user info from Salesforce");
1987
- return null;
1988
- }
1989
- const userMap = await options.mapProfileToUser?.(user);
1990
- return {
1991
- user: {
1992
- id: user.user_id,
1993
- name: user.name,
1994
- email: user.email,
1995
- image: user.photos?.picture || user.photos?.thumbnail,
1996
- emailVerified: user.email_verified ?? false,
1997
- ...userMap
1998
- },
1999
- data: user
2000
- };
2001
- } catch (error) {
2002
- logger.error("Failed to fetch user info from Salesforce:", error);
2003
- return null;
2004
- }
2005
- },
2006
- options
2007
- };
2008
- };
2009
-
2010
- //#endregion
2011
- //#region src/social-providers/slack.ts
2012
- const slack = (options) => {
2013
- return {
2014
- id: "slack",
2015
- name: "Slack",
2016
- createAuthorizationURL({ state, scopes, redirectURI }) {
2017
- const _scopes = options.disableDefaultScope ? [] : [
2018
- "openid",
2019
- "profile",
2020
- "email"
2021
- ];
2022
- if (scopes) _scopes.push(...scopes);
2023
- if (options.scope) _scopes.push(...options.scope);
2024
- const url = new URL("https://slack.com/openid/connect/authorize");
2025
- url.searchParams.set("scope", _scopes.join(" "));
2026
- url.searchParams.set("response_type", "code");
2027
- url.searchParams.set("client_id", options.clientId);
2028
- url.searchParams.set("redirect_uri", options.redirectURI || redirectURI);
2029
- url.searchParams.set("state", state);
2030
- return url;
2031
- },
2032
- validateAuthorizationCode: async ({ code, redirectURI }) => {
2033
- return validateAuthorizationCode({
2034
- code,
2035
- redirectURI,
2036
- options,
2037
- tokenEndpoint: "https://slack.com/api/openid.connect.token"
2038
- });
2039
- },
2040
- refreshAccessToken: options.refreshAccessToken ? options.refreshAccessToken : async (refreshToken) => {
2041
- return refreshAccessToken({
2042
- refreshToken,
2043
- options: {
2044
- clientId: options.clientId,
2045
- clientKey: options.clientKey,
2046
- clientSecret: options.clientSecret
2047
- },
2048
- tokenEndpoint: "https://slack.com/api/openid.connect.token"
2049
- });
2050
- },
2051
- async getUserInfo(token) {
2052
- if (options.getUserInfo) return options.getUserInfo(token);
2053
- const { data: profile, error } = await betterFetch("https://slack.com/api/openid.connect.userInfo", { headers: { authorization: `Bearer ${token.accessToken}` } });
2054
- if (error) return null;
2055
- const userMap = await options.mapProfileToUser?.(profile);
2056
- return {
2057
- user: {
2058
- id: profile["https://slack.com/user_id"],
2059
- name: profile.name || "",
2060
- email: profile.email,
2061
- emailVerified: profile.email_verified,
2062
- image: profile.picture || profile["https://slack.com/user_image_512"],
2063
- ...userMap
2064
- },
2065
- data: profile
2066
- };
2067
- },
2068
- options
2069
- };
2070
- };
2071
-
2072
- //#endregion
2073
- //#region src/social-providers/spotify.ts
2074
- const spotify = (options) => {
2075
- return {
2076
- id: "spotify",
2077
- name: "Spotify",
2078
- createAuthorizationURL({ state, scopes, codeVerifier, redirectURI }) {
2079
- const _scopes = options.disableDefaultScope ? [] : ["user-read-email"];
2080
- if (options.scope) _scopes.push(...options.scope);
2081
- if (scopes) _scopes.push(...scopes);
2082
- return createAuthorizationURL({
2083
- id: "spotify",
2084
- options,
2085
- authorizationEndpoint: "https://accounts.spotify.com/authorize",
2086
- scopes: _scopes,
2087
- state,
2088
- codeVerifier,
2089
- redirectURI
2090
- });
2091
- },
2092
- validateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {
2093
- return validateAuthorizationCode({
2094
- code,
2095
- codeVerifier,
2096
- redirectURI,
2097
- options,
2098
- tokenEndpoint: "https://accounts.spotify.com/api/token"
2099
- });
2100
- },
2101
- refreshAccessToken: options.refreshAccessToken ? options.refreshAccessToken : async (refreshToken) => {
2102
- return refreshAccessToken({
2103
- refreshToken,
2104
- options: {
2105
- clientId: options.clientId,
2106
- clientKey: options.clientKey,
2107
- clientSecret: options.clientSecret
2108
- },
2109
- tokenEndpoint: "https://accounts.spotify.com/api/token"
2110
- });
2111
- },
2112
- async getUserInfo(token) {
2113
- if (options.getUserInfo) return options.getUserInfo(token);
2114
- const { data: profile, error } = await betterFetch("https://api.spotify.com/v1/me", {
2115
- method: "GET",
2116
- headers: { Authorization: `Bearer ${token.accessToken}` }
2117
- });
2118
- if (error) return null;
2119
- const userMap = await options.mapProfileToUser?.(profile);
2120
- return {
2121
- user: {
2122
- id: profile.id,
2123
- name: profile.display_name,
2124
- email: profile.email,
2125
- image: profile.images[0]?.url,
2126
- emailVerified: false,
2127
- ...userMap
2128
- },
2129
- data: profile
2130
- };
2131
- },
2132
- options
2133
- };
2134
- };
2135
-
2136
- //#endregion
2137
- //#region src/social-providers/tiktok.ts
2138
- const tiktok = (options) => {
2139
- return {
2140
- id: "tiktok",
2141
- name: "TikTok",
2142
- createAuthorizationURL({ state, scopes, redirectURI }) {
2143
- const _scopes = options.disableDefaultScope ? [] : ["user.info.profile"];
2144
- if (options.scope) _scopes.push(...options.scope);
2145
- if (scopes) _scopes.push(...scopes);
2146
- return new URL(`https://www.tiktok.com/v2/auth/authorize?scope=${_scopes.join(",")}&response_type=code&client_key=${options.clientKey}&redirect_uri=${encodeURIComponent(options.redirectURI || redirectURI)}&state=${state}`);
2147
- },
2148
- validateAuthorizationCode: async ({ code, redirectURI }) => {
2149
- return validateAuthorizationCode({
2150
- code,
2151
- redirectURI: options.redirectURI || redirectURI,
2152
- options: {
2153
- clientKey: options.clientKey,
2154
- clientSecret: options.clientSecret
2155
- },
2156
- tokenEndpoint: "https://open.tiktokapis.com/v2/oauth/token/"
2157
- });
2158
- },
2159
- refreshAccessToken: options.refreshAccessToken ? options.refreshAccessToken : async (refreshToken) => {
2160
- return refreshAccessToken({
2161
- refreshToken,
2162
- options: { clientSecret: options.clientSecret },
2163
- tokenEndpoint: "https://open.tiktokapis.com/v2/oauth/token/",
2164
- authentication: "post",
2165
- extraParams: { client_key: options.clientKey }
2166
- });
2167
- },
2168
- async getUserInfo(token) {
2169
- if (options.getUserInfo) return options.getUserInfo(token);
2170
- const { data: profile, error } = await betterFetch(`https://open.tiktokapis.com/v2/user/info/?fields=${[
2171
- "open_id",
2172
- "avatar_large_url",
2173
- "display_name",
2174
- "username"
2175
- ].join(",")}`, { headers: { authorization: `Bearer ${token.accessToken}` } });
2176
- if (error) return null;
2177
- return {
2178
- user: {
2179
- email: profile.data.user.email || profile.data.user.username,
2180
- id: profile.data.user.open_id,
2181
- name: profile.data.user.display_name || profile.data.user.username,
2182
- image: profile.data.user.avatar_large_url,
2183
- emailVerified: profile.data.user.email ? true : false
2184
- },
2185
- data: profile
2186
- };
2187
- },
2188
- options
2189
- };
2190
- };
2191
-
2192
- //#endregion
2193
- //#region src/social-providers/twitch.ts
2194
- const twitch = (options) => {
2195
- return {
2196
- id: "twitch",
2197
- name: "Twitch",
2198
- createAuthorizationURL({ state, scopes, redirectURI }) {
2199
- const _scopes = options.disableDefaultScope ? [] : ["user:read:email", "openid"];
2200
- if (options.scope) _scopes.push(...options.scope);
2201
- if (scopes) _scopes.push(...scopes);
2202
- return createAuthorizationURL({
2203
- id: "twitch",
2204
- redirectURI,
2205
- options,
2206
- authorizationEndpoint: "https://id.twitch.tv/oauth2/authorize",
2207
- scopes: _scopes,
2208
- state,
2209
- claims: options.claims || [
2210
- "email",
2211
- "email_verified",
2212
- "preferred_username",
2213
- "picture"
2214
- ]
2215
- });
2216
- },
2217
- validateAuthorizationCode: async ({ code, redirectURI }) => {
2218
- return validateAuthorizationCode({
2219
- code,
2220
- redirectURI,
2221
- options,
2222
- tokenEndpoint: "https://id.twitch.tv/oauth2/token"
2223
- });
2224
- },
2225
- refreshAccessToken: options.refreshAccessToken ? options.refreshAccessToken : async (refreshToken) => {
2226
- return refreshAccessToken({
2227
- refreshToken,
2228
- options: {
2229
- clientId: options.clientId,
2230
- clientKey: options.clientKey,
2231
- clientSecret: options.clientSecret
2232
- },
2233
- tokenEndpoint: "https://id.twitch.tv/oauth2/token"
2234
- });
2235
- },
2236
- async getUserInfo(token) {
2237
- if (options.getUserInfo) return options.getUserInfo(token);
2238
- const idToken = token.idToken;
2239
- if (!idToken) {
2240
- logger.error("No idToken found in token");
2241
- return null;
2242
- }
2243
- const profile = decodeJwt(idToken);
2244
- const userMap = await options.mapProfileToUser?.(profile);
2245
- return {
2246
- user: {
2247
- id: profile.sub,
2248
- name: profile.preferred_username,
2249
- email: profile.email,
2250
- image: profile.picture,
2251
- emailVerified: profile.email_verified,
2252
- ...userMap
2253
- },
2254
- data: profile
2255
- };
2256
- },
2257
- options
2258
- };
2259
- };
2260
-
2261
- //#endregion
2262
- //#region src/social-providers/twitter.ts
2263
- const twitter = (options) => {
2264
- return {
2265
- id: "twitter",
2266
- name: "Twitter",
2267
- createAuthorizationURL(data) {
2268
- const _scopes = options.disableDefaultScope ? [] : [
2269
- "users.read",
2270
- "tweet.read",
2271
- "offline.access",
2272
- "users.email"
2273
- ];
2274
- if (options.scope) _scopes.push(...options.scope);
2275
- if (data.scopes) _scopes.push(...data.scopes);
2276
- return createAuthorizationURL({
2277
- id: "twitter",
2278
- options,
2279
- authorizationEndpoint: "https://x.com/i/oauth2/authorize",
2280
- scopes: _scopes,
2281
- state: data.state,
2282
- codeVerifier: data.codeVerifier,
2283
- redirectURI: data.redirectURI
2284
- });
2285
- },
2286
- validateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {
2287
- return validateAuthorizationCode({
2288
- code,
2289
- codeVerifier,
2290
- authentication: "basic",
2291
- redirectURI,
2292
- options,
2293
- tokenEndpoint: "https://api.x.com/2/oauth2/token"
2294
- });
2295
- },
2296
- refreshAccessToken: options.refreshAccessToken ? options.refreshAccessToken : async (refreshToken) => {
2297
- return refreshAccessToken({
2298
- refreshToken,
2299
- options: {
2300
- clientId: options.clientId,
2301
- clientKey: options.clientKey,
2302
- clientSecret: options.clientSecret
2303
- },
2304
- authentication: "basic",
2305
- tokenEndpoint: "https://api.x.com/2/oauth2/token"
2306
- });
2307
- },
2308
- async getUserInfo(token) {
2309
- if (options.getUserInfo) return options.getUserInfo(token);
2310
- const { data: profile, error: profileError } = await betterFetch("https://api.x.com/2/users/me?user.fields=profile_image_url", {
2311
- method: "GET",
2312
- headers: { Authorization: `Bearer ${token.accessToken}` }
2313
- });
2314
- if (profileError) return null;
2315
- const { data: emailData, error: emailError } = await betterFetch("https://api.x.com/2/users/me?user.fields=confirmed_email", {
2316
- method: "GET",
2317
- headers: { Authorization: `Bearer ${token.accessToken}` }
2318
- });
2319
- let emailVerified = false;
2320
- if (!emailError && emailData?.data?.confirmed_email) {
2321
- profile.data.email = emailData.data.confirmed_email;
2322
- emailVerified = true;
2323
- }
2324
- const userMap = await options.mapProfileToUser?.(profile);
2325
- return {
2326
- user: {
2327
- id: profile.data.id,
2328
- name: profile.data.name,
2329
- email: profile.data.email || profile.data.username || null,
2330
- image: profile.data.profile_image_url,
2331
- emailVerified,
2332
- ...userMap
2333
- },
2334
- data: profile
2335
- };
2336
- },
2337
- options
2338
- };
2339
- };
2340
-
2341
- //#endregion
2342
- //#region src/social-providers/vk.ts
2343
- const vk = (options) => {
2344
- return {
2345
- id: "vk",
2346
- name: "VK",
2347
- async createAuthorizationURL({ state, scopes, codeVerifier, redirectURI }) {
2348
- const _scopes = options.disableDefaultScope ? [] : ["email", "phone"];
2349
- if (options.scope) _scopes.push(...options.scope);
2350
- if (scopes) _scopes.push(...scopes);
2351
- return createAuthorizationURL({
2352
- id: "vk",
2353
- options,
2354
- authorizationEndpoint: "https://id.vk.com/authorize",
2355
- scopes: _scopes,
2356
- state,
2357
- redirectURI,
2358
- codeVerifier
2359
- });
2360
- },
2361
- validateAuthorizationCode: async ({ code, codeVerifier, redirectURI, deviceId }) => {
2362
- return validateAuthorizationCode({
2363
- code,
2364
- codeVerifier,
2365
- redirectURI: options.redirectURI || redirectURI,
2366
- options,
2367
- deviceId,
2368
- tokenEndpoint: "https://id.vk.com/oauth2/auth"
2369
- });
2370
- },
2371
- refreshAccessToken: options.refreshAccessToken ? options.refreshAccessToken : async (refreshToken) => {
2372
- return refreshAccessToken({
2373
- refreshToken,
2374
- options: {
2375
- clientId: options.clientId,
2376
- clientKey: options.clientKey,
2377
- clientSecret: options.clientSecret
2378
- },
2379
- tokenEndpoint: "https://id.vk.com/oauth2/auth"
2380
- });
2381
- },
2382
- async getUserInfo(data) {
2383
- if (options.getUserInfo) return options.getUserInfo(data);
2384
- if (!data.accessToken) return null;
2385
- const formBody = new URLSearchParams({
2386
- access_token: data.accessToken,
2387
- client_id: options.clientId
2388
- }).toString();
2389
- const { data: profile, error } = await betterFetch("https://id.vk.com/oauth2/user_info", {
2390
- method: "POST",
2391
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
2392
- body: formBody
2393
- });
2394
- if (error) return null;
2395
- const userMap = await options.mapProfileToUser?.(profile);
2396
- if (!profile.user.email && !userMap?.email) return null;
2397
- return {
2398
- user: {
2399
- id: profile.user.user_id,
2400
- first_name: profile.user.first_name,
2401
- last_name: profile.user.last_name,
2402
- email: profile.user.email,
2403
- image: profile.user.avatar,
2404
- emailVerified: !!profile.user.email,
2405
- birthday: profile.user.birthday,
2406
- sex: profile.user.sex,
2407
- name: `${profile.user.first_name} ${profile.user.last_name}`,
2408
- ...userMap
2409
- },
2410
- data: profile
2411
- };
2412
- },
2413
- options
2414
- };
2415
- };
2416
-
2417
- //#endregion
2418
- //#region src/social-providers/zoom.ts
2419
- const zoom = (userOptions) => {
2420
- const options = {
2421
- pkce: true,
2422
- ...userOptions
2423
- };
2424
- return {
2425
- id: "zoom",
2426
- name: "Zoom",
2427
- createAuthorizationURL: async ({ state, redirectURI, codeVerifier }) => {
2428
- const params = new URLSearchParams({
2429
- response_type: "code",
2430
- redirect_uri: options.redirectURI ? options.redirectURI : redirectURI,
2431
- client_id: options.clientId,
2432
- state
2433
- });
2434
- if (options.pkce) {
2435
- const codeChallenge = await generateCodeChallenge(codeVerifier);
2436
- params.set("code_challenge_method", "S256");
2437
- params.set("code_challenge", codeChallenge);
2438
- }
2439
- const url = new URL("https://zoom.us/oauth/authorize");
2440
- url.search = params.toString();
2441
- return url;
2442
- },
2443
- validateAuthorizationCode: async ({ code, redirectURI, codeVerifier }) => {
2444
- return validateAuthorizationCode({
2445
- code,
2446
- redirectURI: options.redirectURI || redirectURI,
2447
- codeVerifier,
2448
- options,
2449
- tokenEndpoint: "https://zoom.us/oauth/token",
2450
- authentication: "post"
2451
- });
2452
- },
2453
- async getUserInfo(token) {
2454
- if (options.getUserInfo) return options.getUserInfo(token);
2455
- const { data: profile, error } = await betterFetch("https://api.zoom.us/v2/users/me", { headers: { authorization: `Bearer ${token.accessToken}` } });
2456
- if (error) return null;
2457
- const userMap = await options.mapProfileToUser?.(profile);
2458
- return {
2459
- user: {
2460
- id: profile.id,
2461
- name: profile.display_name,
2462
- image: profile.pic_url,
2463
- email: profile.email,
2464
- emailVerified: Boolean(profile.verified),
2465
- ...userMap
2466
- },
2467
- data: { ...profile }
2468
- };
2469
- }
2470
- };
2471
- };
2472
-
2473
162
  //#endregion
2474
163
  //#region src/social-providers/index.ts
2475
164
  const socialProviders = {
2476
- apple,
2477
- atlassian,
2478
- cognito,
2479
- discord,
2480
- facebook,
2481
- figma,
2482
165
  github,
2483
- microsoft,
2484
- google,
2485
- huggingface,
2486
- slack,
2487
- spotify,
2488
- twitch,
2489
- twitter,
2490
- dropbox,
2491
- kick,
2492
- linear,
2493
- linkedin,
2494
- gitlab,
2495
- tiktok,
2496
- reddit,
2497
- roblox,
2498
- salesforce,
2499
- vk,
2500
- zoom,
2501
- notion,
2502
- kakao,
2503
- naver,
2504
- line,
2505
- paybin,
2506
- paypal,
2507
- polar
166
+ google
2508
167
  };
2509
168
  const socialProviderList = Object.keys(socialProviders);
2510
169
  const SocialProviderListEnum = z$1.enum(socialProviderList).or(z$1.string());
2511
170
 
2512
171
  //#endregion
2513
- export { SocialProviderListEnum, apple, atlassian, cognito, discord, dropbox, facebook, figma, getApplePublicKey, getCognitoPublicKey, github, gitlab, google, huggingface, kakao, kick, line, linear, linkedin, microsoft, naver, notion, paybin, paypal, polar, reddit, roblox, salesforce, slack, socialProviderList, socialProviders, spotify, tiktok, twitch, twitter, vk, zoom };
172
+ export { SocialProviderListEnum, github, google, socialProviderList, socialProviders };