@better-auth/core 1.7.0-beta.4 → 1.7.0-beta.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. package/dist/api/index.d.mts +47 -4
  2. package/dist/api/index.mjs +40 -1
  3. package/dist/context/global.mjs +1 -1
  4. package/dist/context/transaction.d.mts +7 -4
  5. package/dist/context/transaction.mjs +6 -3
  6. package/dist/db/adapter/factory.mjs +57 -31
  7. package/dist/db/adapter/index.d.mts +54 -10
  8. package/dist/db/adapter/types.d.mts +1 -1
  9. package/dist/db/get-tables.mjs +3 -3
  10. package/dist/db/schema/account.d.mts +1 -1
  11. package/dist/db/schema/account.mjs +1 -1
  12. package/dist/db/type.d.mts +12 -7
  13. package/dist/env/env-impl.mjs +1 -1
  14. package/dist/error/codes.d.mts +5 -0
  15. package/dist/error/codes.mjs +5 -0
  16. package/dist/index.d.mts +2 -2
  17. package/dist/instrumentation/tracer.mjs +1 -1
  18. package/dist/oauth2/create-authorization-url.d.mts +4 -1
  19. package/dist/oauth2/create-authorization-url.mjs +5 -2
  20. package/dist/oauth2/dpop.d.mts +142 -0
  21. package/dist/oauth2/dpop.mjs +246 -0
  22. package/dist/oauth2/index.d.mts +6 -3
  23. package/dist/oauth2/index.mjs +5 -2
  24. package/dist/oauth2/oauth-provider.d.mts +128 -9
  25. package/dist/oauth2/refresh-access-token.mjs +1 -1
  26. package/dist/oauth2/scopes.d.mts +76 -0
  27. package/dist/oauth2/scopes.mjs +96 -0
  28. package/dist/oauth2/utils.mjs +2 -1
  29. package/dist/oauth2/verify-id-token.d.mts +26 -0
  30. package/dist/oauth2/verify-id-token.mjs +62 -0
  31. package/dist/oauth2/verify.d.mts +88 -15
  32. package/dist/oauth2/verify.mjs +187 -19
  33. package/dist/social-providers/apple.d.mts +14 -2
  34. package/dist/social-providers/apple.mjs +12 -36
  35. package/dist/social-providers/atlassian.d.mts +5 -1
  36. package/dist/social-providers/atlassian.mjs +4 -4
  37. package/dist/social-providers/cognito.d.mts +13 -2
  38. package/dist/social-providers/cognito.mjs +24 -32
  39. package/dist/social-providers/discord.d.mts +5 -1
  40. package/dist/social-providers/discord.mjs +7 -6
  41. package/dist/social-providers/dropbox.d.mts +5 -1
  42. package/dist/social-providers/dropbox.mjs +5 -5
  43. package/dist/social-providers/facebook.d.mts +21 -2
  44. package/dist/social-providers/facebook.mjs +46 -22
  45. package/dist/social-providers/figma.d.mts +5 -1
  46. package/dist/social-providers/figma.mjs +5 -5
  47. package/dist/social-providers/github.d.mts +5 -1
  48. package/dist/social-providers/github.mjs +4 -4
  49. package/dist/social-providers/gitlab.d.mts +5 -1
  50. package/dist/social-providers/gitlab.mjs +6 -6
  51. package/dist/social-providers/google.d.mts +29 -3
  52. package/dist/social-providers/google.mjs +24 -30
  53. package/dist/social-providers/huggingface.d.mts +5 -1
  54. package/dist/social-providers/huggingface.mjs +8 -8
  55. package/dist/social-providers/index.d.mts +222 -42
  56. package/dist/social-providers/kakao.d.mts +5 -1
  57. package/dist/social-providers/kakao.mjs +8 -8
  58. package/dist/social-providers/kick.d.mts +5 -1
  59. package/dist/social-providers/kick.mjs +4 -4
  60. package/dist/social-providers/line.d.mts +8 -2
  61. package/dist/social-providers/line.mjs +12 -14
  62. package/dist/social-providers/linear.d.mts +5 -1
  63. package/dist/social-providers/linear.mjs +4 -4
  64. package/dist/social-providers/linkedin.d.mts +5 -1
  65. package/dist/social-providers/linkedin.mjs +10 -10
  66. package/dist/social-providers/microsoft-entra-id.d.mts +41 -6
  67. package/dist/social-providers/microsoft-entra-id.mjs +40 -36
  68. package/dist/social-providers/naver.d.mts +5 -1
  69. package/dist/social-providers/naver.mjs +4 -4
  70. package/dist/social-providers/notion.d.mts +5 -1
  71. package/dist/social-providers/notion.mjs +4 -4
  72. package/dist/social-providers/paybin.d.mts +5 -1
  73. package/dist/social-providers/paybin.mjs +10 -10
  74. package/dist/social-providers/paypal.d.mts +5 -2
  75. package/dist/social-providers/paypal.mjs +8 -13
  76. package/dist/social-providers/polar.d.mts +5 -1
  77. package/dist/social-providers/polar.mjs +8 -8
  78. package/dist/social-providers/railway.d.mts +5 -1
  79. package/dist/social-providers/railway.mjs +9 -9
  80. package/dist/social-providers/reddit.d.mts +5 -1
  81. package/dist/social-providers/reddit.mjs +9 -8
  82. package/dist/social-providers/roblox.d.mts +5 -1
  83. package/dist/social-providers/roblox.mjs +5 -5
  84. package/dist/social-providers/salesforce.d.mts +5 -1
  85. package/dist/social-providers/salesforce.mjs +8 -8
  86. package/dist/social-providers/slack.d.mts +5 -1
  87. package/dist/social-providers/slack.mjs +9 -9
  88. package/dist/social-providers/spotify.d.mts +5 -1
  89. package/dist/social-providers/spotify.mjs +5 -5
  90. package/dist/social-providers/tiktok.d.mts +5 -1
  91. package/dist/social-providers/tiktok.mjs +9 -5
  92. package/dist/social-providers/twitch.d.mts +5 -1
  93. package/dist/social-providers/twitch.mjs +4 -4
  94. package/dist/social-providers/twitter.d.mts +6 -4
  95. package/dist/social-providers/twitter.mjs +9 -9
  96. package/dist/social-providers/vercel.d.mts +5 -1
  97. package/dist/social-providers/vercel.mjs +4 -7
  98. package/dist/social-providers/vk.d.mts +5 -1
  99. package/dist/social-providers/vk.mjs +5 -5
  100. package/dist/social-providers/wechat.d.mts +5 -1
  101. package/dist/social-providers/wechat.mjs +10 -6
  102. package/dist/social-providers/zoom.d.mts +6 -1
  103. package/dist/social-providers/zoom.mjs +15 -9
  104. package/dist/types/context.d.mts +27 -8
  105. package/dist/types/index.d.mts +1 -1
  106. package/dist/types/init-options.d.mts +137 -6
  107. package/dist/types/plugin-client.d.mts +12 -2
  108. package/dist/utils/host.mjs +4 -0
  109. package/dist/utils/url.mjs +4 -3
  110. package/package.json +7 -7
  111. package/src/api/index.ts +82 -0
  112. package/src/context/transaction.ts +45 -12
  113. package/src/db/adapter/factory.ts +127 -64
  114. package/src/db/adapter/index.ts +54 -9
  115. package/src/db/adapter/types.ts +1 -0
  116. package/src/db/get-tables.ts +8 -3
  117. package/src/db/schema/account.ts +14 -2
  118. package/src/db/type.ts +12 -7
  119. package/src/env/env-impl.ts +1 -2
  120. package/src/error/codes.ts +5 -0
  121. package/src/oauth2/create-authorization-url.ts +2 -2
  122. package/src/oauth2/dpop.ts +568 -0
  123. package/src/oauth2/index.ts +61 -2
  124. package/src/oauth2/oauth-provider.ts +140 -10
  125. package/src/oauth2/refresh-access-token.ts +2 -2
  126. package/src/oauth2/scopes.ts +118 -0
  127. package/src/oauth2/utils.ts +2 -5
  128. package/src/oauth2/verify-id-token.ts +111 -0
  129. package/src/oauth2/verify.ts +372 -58
  130. package/src/social-providers/apple.ts +24 -61
  131. package/src/social-providers/atlassian.ts +12 -8
  132. package/src/social-providers/cognito.ts +25 -47
  133. package/src/social-providers/discord.ts +19 -8
  134. package/src/social-providers/dropbox.ts +13 -7
  135. package/src/social-providers/facebook.ts +97 -51
  136. package/src/social-providers/figma.ts +13 -9
  137. package/src/social-providers/github.ts +12 -8
  138. package/src/social-providers/gitlab.ts +14 -8
  139. package/src/social-providers/google.ts +66 -47
  140. package/src/social-providers/huggingface.ts +12 -8
  141. package/src/social-providers/kakao.ts +16 -8
  142. package/src/social-providers/kick.ts +12 -7
  143. package/src/social-providers/line.ts +37 -37
  144. package/src/social-providers/linear.ts +12 -6
  145. package/src/social-providers/linkedin.ts +14 -10
  146. package/src/social-providers/microsoft-entra-id.ts +103 -59
  147. package/src/social-providers/naver.ts +12 -6
  148. package/src/social-providers/notion.ts +12 -6
  149. package/src/social-providers/paybin.ts +14 -11
  150. package/src/social-providers/paypal.ts +6 -25
  151. package/src/social-providers/polar.ts +12 -8
  152. package/src/social-providers/railway.ts +13 -9
  153. package/src/social-providers/reddit.ts +25 -10
  154. package/src/social-providers/roblox.ts +18 -7
  155. package/src/social-providers/salesforce.ts +12 -8
  156. package/src/social-providers/slack.ts +18 -9
  157. package/src/social-providers/spotify.ts +13 -7
  158. package/src/social-providers/tiktok.ts +13 -7
  159. package/src/social-providers/twitch.ts +12 -8
  160. package/src/social-providers/twitter.ts +17 -8
  161. package/src/social-providers/vercel.ts +16 -10
  162. package/src/social-providers/vk.ts +13 -7
  163. package/src/social-providers/wechat.ts +28 -9
  164. package/src/social-providers/zoom.ts +19 -6
  165. package/src/types/context.ts +26 -8
  166. package/src/types/index.ts +7 -0
  167. package/src/types/init-options.ts +159 -8
  168. package/src/types/plugin-client.ts +16 -2
  169. package/src/utils/host.ts +15 -0
  170. package/src/utils/url.ts +10 -4
@@ -1,24 +1,24 @@
1
1
  import { logger } from "../env/logger.mjs";
2
+ import { resolveRequestedScopes } from "../oauth2/scopes.mjs";
2
3
  import { getOAuth2Tokens } from "../oauth2/utils.mjs";
3
4
  import { createAuthorizationURL } from "../oauth2/create-authorization-url.mjs";
4
5
  import { refreshAccessToken } from "../oauth2/refresh-access-token.mjs";
5
6
  import { authorizationCodeRequest } from "../oauth2/validate-authorization-code.mjs";
6
7
  import { betterFetch } from "@better-fetch/fetch";
7
8
  //#region src/social-providers/github.ts
9
+ const GITHUB_DEFAULT_SCOPES = ["read:user", "user:email"];
8
10
  const github = (options) => {
9
11
  const tokenEndpoint = "https://github.com/login/oauth/access_token";
10
12
  return {
11
13
  id: "github",
12
14
  name: "GitHub",
15
+ callbackPath: "/callback/github",
13
16
  createAuthorizationURL({ state, scopes, loginHint, codeVerifier, redirectURI, additionalParams }) {
14
- const _scopes = options.disableDefaultScope ? [] : ["read:user", "user:email"];
15
- if (options.scope) _scopes.push(...options.scope);
16
- if (scopes) _scopes.push(...scopes);
17
17
  return createAuthorizationURL({
18
18
  id: "github",
19
19
  options,
20
20
  authorizationEndpoint: "https://github.com/login/oauth/authorize",
21
- scopes: _scopes,
21
+ scopes: resolveRequestedScopes(options, GITHUB_DEFAULT_SCOPES, scopes),
22
22
  state,
23
23
  codeVerifier,
24
24
  redirectURI,
@@ -52,6 +52,7 @@ interface GitlabOptions extends ProviderOptions<GitlabProfile> {
52
52
  declare const gitlab: (options: GitlabOptions) => {
53
53
  id: "gitlab";
54
54
  name: string;
55
+ callbackPath: string;
55
56
  createAuthorizationURL: ({
56
57
  state,
57
58
  scopes,
@@ -67,7 +68,10 @@ declare const gitlab: (options: GitlabOptions) => {
67
68
  display?: string | undefined;
68
69
  loginHint?: string | undefined;
69
70
  additionalParams?: Record<string, string> | undefined;
70
- }) => Promise<URL>;
71
+ }) => Promise<{
72
+ url: URL;
73
+ requestedScopes: string[];
74
+ }>;
71
75
  validateAuthorizationCode: ({
72
76
  code,
73
77
  redirectURI,
@@ -1,3 +1,4 @@
1
+ import { resolveRequestedScopes } from "../oauth2/scopes.mjs";
1
2
  import { createAuthorizationURL } from "../oauth2/create-authorization-url.mjs";
2
3
  import { refreshAccessToken } from "../oauth2/refresh-access-token.mjs";
3
4
  import { validateAuthorizationCode } from "../oauth2/validate-authorization-code.mjs";
@@ -14,21 +15,20 @@ const issuerToEndpoints = (issuer) => {
14
15
  userinfoEndpoint: cleanDoubleSlashes(`${baseUrl}/api/v4/user`)
15
16
  };
16
17
  };
18
+ const GITLAB_DEFAULT_SCOPES = ["read_user"];
17
19
  const gitlab = (options) => {
18
20
  const { authorizationEndpoint, tokenEndpoint, userinfoEndpoint } = issuerToEndpoints(options.issuer);
19
21
  const issuerId = "gitlab";
20
22
  return {
21
23
  id: issuerId,
22
24
  name: "Gitlab",
23
- createAuthorizationURL: async ({ state, scopes, codeVerifier, loginHint, redirectURI, additionalParams }) => {
24
- const _scopes = options.disableDefaultScope ? [] : ["read_user"];
25
- if (options.scope) _scopes.push(...options.scope);
26
- if (scopes) _scopes.push(...scopes);
27
- return await createAuthorizationURL({
25
+ callbackPath: "/callback/gitlab",
26
+ createAuthorizationURL: ({ state, scopes, codeVerifier, loginHint, redirectURI, additionalParams }) => {
27
+ return createAuthorizationURL({
28
28
  id: issuerId,
29
29
  options,
30
30
  authorizationEndpoint,
31
- scopes: _scopes,
31
+ scopes: resolveRequestedScopes(options, GITLAB_DEFAULT_SCOPES, scopes),
32
32
  state,
33
33
  redirectURI,
34
34
  codeVerifier,
@@ -1,4 +1,6 @@
1
1
  import { OAuth2Tokens, ProviderOptions } from "../oauth2/oauth-provider.mjs";
2
+ import * as jose from "jose";
3
+
2
4
  //#region src/social-providers/google.d.ts
3
5
  interface GoogleProfile {
4
6
  aud: string;
@@ -37,13 +39,28 @@ interface GoogleOptions extends ProviderOptions<GoogleProfile> {
37
39
  */
38
40
  display?: ("page" | "popup" | "touch" | "wap") | undefined;
39
41
  /**
40
- * The hosted domain of the user
42
+ * The hosted domain (Google Workspace) the user must belong to.
43
+ *
44
+ * This is sent to Google as the `hd` authorization hint and, when set, is
45
+ * also enforced against the `hd` claim of the returned id token/profile.
46
+ * Sign-in is rejected when the claim is missing or does not match, so this
47
+ * can be used to restrict sign-in to a Workspace domain.
41
48
  */
42
49
  hd?: string | undefined;
50
+ /**
51
+ * Enable incremental authorization via Google's `include_granted_scopes`
52
+ * parameter. When enabled, Google reports the user's full granted scope set
53
+ * in the token response.
54
+ *
55
+ * @default true
56
+ */
57
+ includeGrantedScopes?: boolean | undefined;
43
58
  }
44
59
  declare const google: (options: GoogleOptions) => {
45
60
  id: "google";
46
61
  name: string;
62
+ callbackPath: string;
63
+ grantAuthority: "full-grant" | "projection";
47
64
  createAuthorizationURL({
48
65
  state,
49
66
  scopes,
@@ -60,7 +77,10 @@ declare const google: (options: GoogleOptions) => {
60
77
  display?: string | undefined;
61
78
  loginHint?: string | undefined;
62
79
  additionalParams?: Record<string, string> | undefined;
63
- }): Promise<URL>;
80
+ }): Promise<{
81
+ url: URL;
82
+ requestedScopes: string[];
83
+ }>;
64
84
  validateAuthorizationCode: ({
65
85
  code,
66
86
  codeVerifier,
@@ -72,7 +92,13 @@ declare const google: (options: GoogleOptions) => {
72
92
  deviceId?: string | undefined;
73
93
  }) => Promise<OAuth2Tokens>;
74
94
  refreshAccessToken: (refreshToken: string) => Promise<OAuth2Tokens>;
75
- verifyIdToken(token: string, nonce: string | undefined): Promise<boolean>;
95
+ idToken: {
96
+ jwks: (header: jose.JWTHeaderParameters) => Promise<Uint8Array<ArrayBufferLike> | CryptoKey>;
97
+ issuer: string[];
98
+ audience: string | string[];
99
+ maxTokenAge: string;
100
+ verifyClaims: ((claims: Record<string, unknown>) => boolean) | undefined;
101
+ };
76
102
  getUserInfo(token: OAuth2Tokens & {
77
103
  user?: {
78
104
  name?: {
@@ -1,34 +1,35 @@
1
1
  import { APIError, BetterAuthError } from "../error/index.mjs";
2
2
  import { logger } from "../env/logger.mjs";
3
+ import { resolveRequestedScopes } from "../oauth2/scopes.mjs";
3
4
  import { getPrimaryClientId } from "../oauth2/utils.mjs";
4
5
  import { createAuthorizationURL } from "../oauth2/create-authorization-url.mjs";
5
6
  import { refreshAccessToken } from "../oauth2/refresh-access-token.mjs";
6
7
  import { validateAuthorizationCode } from "../oauth2/validate-authorization-code.mjs";
7
- import { decodeJwt, decodeProtectedHeader, importJWK, jwtVerify } from "jose";
8
+ import { decodeJwt, importJWK } from "jose";
8
9
  import { betterFetch } from "@better-fetch/fetch";
9
10
  //#region src/social-providers/google.ts
11
+ const GOOGLE_DEFAULT_SCOPES = [
12
+ "email",
13
+ "profile",
14
+ "openid"
15
+ ];
10
16
  const google = (options) => {
11
17
  return {
12
18
  id: "google",
13
19
  name: "Google",
20
+ callbackPath: "/callback/google",
21
+ grantAuthority: options.includeGrantedScopes !== false ? "full-grant" : "projection",
14
22
  async createAuthorizationURL({ state, scopes, codeVerifier, redirectURI, loginHint, display, additionalParams }) {
15
23
  if (!getPrimaryClientId(options.clientId) || !options.clientSecret) {
16
24
  logger.error("Client Id and Client Secret is required for Google. Make sure to provide them in the options.");
17
25
  throw new BetterAuthError("CLIENT_ID_AND_SECRET_REQUIRED");
18
26
  }
19
27
  if (!codeVerifier) throw new BetterAuthError("codeVerifier is required for Google");
20
- const _scopes = options.disableDefaultScope ? [] : [
21
- "email",
22
- "profile",
23
- "openid"
24
- ];
25
- if (options.scope) _scopes.push(...options.scope);
26
- if (scopes) _scopes.push(...scopes);
27
- return await createAuthorizationURL({
28
+ return createAuthorizationURL({
28
29
  id: "google",
29
30
  options,
30
31
  authorizationEndpoint: "https://accounts.google.com/o/oauth2/v2/auth",
31
- scopes: _scopes,
32
+ scopes: resolveRequestedScopes(options, GOOGLE_DEFAULT_SCOPES, scopes),
32
33
  state,
33
34
  codeVerifier,
34
35
  redirectURI,
@@ -37,9 +38,9 @@ const google = (options) => {
37
38
  display: display || options.display,
38
39
  loginHint,
39
40
  hd: options.hd,
40
- additionalParams: {
41
- include_granted_scopes: "true",
42
- ...additionalParams ?? {}
41
+ additionalParams: options.includeGrantedScopes === false ? { ...additionalParams ?? {} } : {
42
+ ...additionalParams ?? {},
43
+ include_granted_scopes: "true"
43
44
  }
44
45
  });
45
46
  },
@@ -63,28 +64,21 @@ const google = (options) => {
63
64
  tokenEndpoint: "https://oauth2.googleapis.com/token"
64
65
  });
65
66
  },
66
- async verifyIdToken(token, nonce) {
67
- if (options.disableIdTokenSignIn) return false;
68
- if (options.verifyIdToken) return options.verifyIdToken(token, nonce);
69
- try {
70
- const { kid, alg: jwtAlg } = decodeProtectedHeader(token);
71
- if (!kid || !jwtAlg) return false;
72
- const { payload: jwtClaims } = await jwtVerify(token, await getGooglePublicKey(kid), {
73
- algorithms: [jwtAlg],
74
- issuer: ["https://accounts.google.com", "accounts.google.com"],
75
- audience: options.clientId,
76
- maxTokenAge: "1h"
77
- });
78
- if (nonce && jwtClaims.nonce !== nonce) return false;
79
- return true;
80
- } catch {
81
- return false;
82
- }
67
+ idToken: {
68
+ jwks: (header) => getGooglePublicKey(header.kid),
69
+ issuer: ["https://accounts.google.com", "accounts.google.com"],
70
+ audience: options.clientId,
71
+ maxTokenAge: "1h",
72
+ verifyClaims: options.hd ? (claims) => claims.hd === options.hd : void 0
83
73
  },
84
74
  async getUserInfo(token) {
85
75
  if (options.getUserInfo) return options.getUserInfo(token);
86
76
  if (!token.idToken) return null;
87
77
  const user = decodeJwt(token.idToken);
78
+ if (options.hd && user.hd !== options.hd) {
79
+ logger.error(`Google sign-in rejected: id token hosted domain (hd) "${user.hd ?? "<missing>"}" does not match the configured "hd" option "${options.hd}".`);
80
+ return null;
81
+ }
88
82
  const userMap = await options.mapProfileToUser?.(user);
89
83
  return {
90
84
  user: {
@@ -34,6 +34,7 @@ interface HuggingFaceOptions extends ProviderOptions<HuggingFaceProfile> {
34
34
  declare const huggingface: (options: HuggingFaceOptions) => {
35
35
  id: "huggingface";
36
36
  name: string;
37
+ callbackPath: string;
37
38
  createAuthorizationURL({
38
39
  state,
39
40
  scopes,
@@ -48,7 +49,10 @@ declare const huggingface: (options: HuggingFaceOptions) => {
48
49
  display?: string | undefined;
49
50
  loginHint?: string | undefined;
50
51
  additionalParams?: Record<string, string> | undefined;
51
- }): Promise<URL>;
52
+ }): Promise<{
53
+ url: URL;
54
+ requestedScopes: string[];
55
+ }>;
52
56
  validateAuthorizationCode: ({
53
57
  code,
54
58
  codeVerifier,
@@ -1,26 +1,26 @@
1
+ import { resolveRequestedScopes } from "../oauth2/scopes.mjs";
1
2
  import { createAuthorizationURL } from "../oauth2/create-authorization-url.mjs";
2
3
  import { refreshAccessToken } from "../oauth2/refresh-access-token.mjs";
3
4
  import { validateAuthorizationCode } from "../oauth2/validate-authorization-code.mjs";
4
5
  import { betterFetch } from "@better-fetch/fetch";
5
6
  //#region src/social-providers/huggingface.ts
7
+ const HUGGINGFACE_DEFAULT_SCOPES = [
8
+ "openid",
9
+ "profile",
10
+ "email"
11
+ ];
6
12
  const huggingface = (options) => {
7
13
  const tokenEndpoint = "https://huggingface.co/oauth/token";
8
14
  return {
9
15
  id: "huggingface",
10
16
  name: "Hugging Face",
17
+ callbackPath: "/callback/huggingface",
11
18
  createAuthorizationURL({ state, scopes, codeVerifier, redirectURI, additionalParams }) {
12
- const _scopes = options.disableDefaultScope ? [] : [
13
- "openid",
14
- "profile",
15
- "email"
16
- ];
17
- if (options.scope) _scopes.push(...options.scope);
18
- if (scopes) _scopes.push(...scopes);
19
19
  return createAuthorizationURL({
20
20
  id: "huggingface",
21
21
  options,
22
22
  authorizationEndpoint: "https://huggingface.co/oauth/authorize",
23
- scopes: _scopes,
23
+ scopes: resolveRequestedScopes(options, HUGGINGFACE_DEFAULT_SCOPES, scopes),
24
24
  state,
25
25
  codeVerifier,
26
26
  redirectURI,