@better-auth/core 1.7.0-beta.3 → 1.7.0-beta.5

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 (188) hide show
  1. package/dist/api/index.d.mts +3 -3
  2. package/dist/context/global.mjs +1 -1
  3. package/dist/db/adapter/factory.mjs +62 -0
  4. package/dist/db/adapter/index.d.mts +35 -1
  5. package/dist/db/adapter/types.d.mts +1 -1
  6. package/dist/db/get-tables.mjs +3 -3
  7. package/dist/db/schema/account.d.mts +1 -1
  8. package/dist/db/schema/account.mjs +1 -1
  9. package/dist/db/type.d.mts +12 -0
  10. package/dist/env/env-impl.mjs +1 -1
  11. package/dist/error/codes.d.mts +6 -0
  12. package/dist/error/codes.mjs +6 -0
  13. package/dist/index.d.mts +2 -2
  14. package/dist/instrumentation/tracer.mjs +1 -1
  15. package/dist/oauth2/authorization-params.d.mts +12 -0
  16. package/dist/oauth2/authorization-params.mjs +12 -0
  17. package/dist/oauth2/basic-credentials.d.mts +30 -0
  18. package/dist/oauth2/basic-credentials.mjs +64 -0
  19. package/dist/oauth2/client-assertion.d.mts +38 -22
  20. package/dist/oauth2/client-assertion.mjs +63 -28
  21. package/dist/oauth2/client-credentials-token.d.mts +19 -40
  22. package/dist/oauth2/client-credentials-token.mjs +18 -29
  23. package/dist/oauth2/create-authorization-url.d.mts +13 -2
  24. package/dist/oauth2/create-authorization-url.mjs +28 -7
  25. package/dist/oauth2/index.d.mts +13 -8
  26. package/dist/oauth2/index.mjs +11 -7
  27. package/dist/oauth2/oauth-provider.d.mts +149 -11
  28. package/dist/oauth2/refresh-access-token.d.mts +20 -40
  29. package/dist/oauth2/refresh-access-token.mjs +20 -33
  30. package/dist/oauth2/scopes.d.mts +76 -0
  31. package/dist/oauth2/scopes.mjs +96 -0
  32. package/dist/oauth2/token-endpoint-auth.d.mts +17 -0
  33. package/dist/oauth2/token-endpoint-auth.mjs +89 -0
  34. package/dist/oauth2/utils.d.mts +9 -1
  35. package/dist/oauth2/utils.mjs +14 -2
  36. package/dist/oauth2/validate-authorization-code.d.mts +17 -52
  37. package/dist/oauth2/validate-authorization-code.mjs +17 -30
  38. package/dist/oauth2/verify-id-token.d.mts +26 -0
  39. package/dist/oauth2/verify-id-token.mjs +62 -0
  40. package/dist/oauth2/verify.d.mts +14 -0
  41. package/dist/oauth2/verify.mjs +38 -12
  42. package/dist/social-providers/apple.d.mts +18 -20
  43. package/dist/social-providers/apple.mjs +15 -28
  44. package/dist/social-providers/atlassian.d.mts +8 -2
  45. package/dist/social-providers/atlassian.mjs +9 -6
  46. package/dist/social-providers/cognito.d.mts +29 -3
  47. package/dist/social-providers/cognito.mjs +30 -34
  48. package/dist/social-providers/discord.d.mts +8 -2
  49. package/dist/social-providers/discord.mjs +20 -6
  50. package/dist/social-providers/dropbox.d.mts +8 -2
  51. package/dist/social-providers/dropbox.mjs +10 -9
  52. package/dist/social-providers/facebook.d.mts +24 -3
  53. package/dist/social-providers/facebook.mjs +51 -24
  54. package/dist/social-providers/figma.d.mts +8 -2
  55. package/dist/social-providers/figma.mjs +8 -7
  56. package/dist/social-providers/github.d.mts +8 -2
  57. package/dist/social-providers/github.mjs +9 -8
  58. package/dist/social-providers/gitlab.d.mts +8 -2
  59. package/dist/social-providers/gitlab.mjs +8 -7
  60. package/dist/social-providers/google.d.mts +32 -4
  61. package/dist/social-providers/google.mjs +26 -29
  62. package/dist/social-providers/huggingface.d.mts +8 -2
  63. package/dist/social-providers/huggingface.mjs +11 -10
  64. package/dist/social-providers/index.d.mts +322 -75
  65. package/dist/social-providers/kakao.d.mts +8 -2
  66. package/dist/social-providers/kakao.mjs +11 -10
  67. package/dist/social-providers/kick.d.mts +8 -2
  68. package/dist/social-providers/kick.mjs +7 -6
  69. package/dist/social-providers/line.d.mts +11 -3
  70. package/dist/social-providers/line.mjs +14 -15
  71. package/dist/social-providers/linear.d.mts +8 -2
  72. package/dist/social-providers/linear.mjs +7 -6
  73. package/dist/social-providers/linkedin.d.mts +8 -2
  74. package/dist/social-providers/linkedin.mjs +12 -11
  75. package/dist/social-providers/microsoft-entra-id.d.mts +33 -7
  76. package/dist/social-providers/microsoft-entra-id.mjs +28 -38
  77. package/dist/social-providers/naver.d.mts +8 -2
  78. package/dist/social-providers/naver.mjs +7 -6
  79. package/dist/social-providers/notion.d.mts +8 -2
  80. package/dist/social-providers/notion.mjs +9 -6
  81. package/dist/social-providers/paybin.d.mts +8 -2
  82. package/dist/social-providers/paybin.mjs +12 -11
  83. package/dist/social-providers/paypal.d.mts +8 -3
  84. package/dist/social-providers/paypal.mjs +10 -14
  85. package/dist/social-providers/polar.d.mts +8 -2
  86. package/dist/social-providers/polar.mjs +11 -10
  87. package/dist/social-providers/railway.d.mts +8 -2
  88. package/dist/social-providers/railway.mjs +11 -10
  89. package/dist/social-providers/reddit.d.mts +8 -2
  90. package/dist/social-providers/reddit.mjs +11 -9
  91. package/dist/social-providers/roblox.d.mts +8 -2
  92. package/dist/social-providers/roblox.mjs +15 -5
  93. package/dist/social-providers/salesforce.d.mts +8 -2
  94. package/dist/social-providers/salesforce.mjs +11 -10
  95. package/dist/social-providers/slack.d.mts +8 -2
  96. package/dist/social-providers/slack.mjs +18 -15
  97. package/dist/social-providers/spotify.d.mts +8 -2
  98. package/dist/social-providers/spotify.mjs +7 -6
  99. package/dist/social-providers/tiktok.d.mts +8 -2
  100. package/dist/social-providers/tiktok.mjs +21 -5
  101. package/dist/social-providers/twitch.d.mts +8 -2
  102. package/dist/social-providers/twitch.mjs +7 -6
  103. package/dist/social-providers/twitter.d.mts +7 -2
  104. package/dist/social-providers/twitter.mjs +11 -10
  105. package/dist/social-providers/vercel.d.mts +8 -2
  106. package/dist/social-providers/vercel.mjs +7 -9
  107. package/dist/social-providers/vk.d.mts +8 -2
  108. package/dist/social-providers/vk.mjs +7 -6
  109. package/dist/social-providers/wechat.d.mts +8 -2
  110. package/dist/social-providers/wechat.mjs +16 -6
  111. package/dist/social-providers/zoom.d.mts +10 -3
  112. package/dist/social-providers/zoom.mjs +14 -15
  113. package/dist/types/context.d.mts +33 -11
  114. package/dist/types/index.d.mts +1 -1
  115. package/dist/types/init-options.d.mts +121 -6
  116. package/dist/utils/ip.d.mts +5 -4
  117. package/dist/utils/ip.mjs +3 -3
  118. package/dist/utils/redirect-uri.d.mts +20 -0
  119. package/dist/utils/redirect-uri.mjs +48 -0
  120. package/dist/utils/string.d.mts +5 -1
  121. package/dist/utils/string.mjs +20 -1
  122. package/dist/utils/url.d.mts +18 -1
  123. package/dist/utils/url.mjs +30 -1
  124. package/package.json +13 -12
  125. package/src/db/adapter/factory.ts +126 -0
  126. package/src/db/adapter/index.ts +32 -0
  127. package/src/db/adapter/types.ts +1 -0
  128. package/src/db/get-tables.ts +8 -3
  129. package/src/db/schema/account.ts +14 -2
  130. package/src/db/type.ts +12 -0
  131. package/src/env/env-impl.ts +1 -2
  132. package/src/error/codes.ts +6 -0
  133. package/src/oauth2/authorization-params.ts +28 -0
  134. package/src/oauth2/basic-credentials.ts +87 -0
  135. package/src/oauth2/client-assertion.ts +131 -58
  136. package/src/oauth2/client-credentials-token.ts +48 -72
  137. package/src/oauth2/create-authorization-url.ts +30 -8
  138. package/src/oauth2/index.ts +42 -10
  139. package/src/oauth2/oauth-provider.ts +161 -12
  140. package/src/oauth2/refresh-access-token.ts +52 -78
  141. package/src/oauth2/scopes.ts +118 -0
  142. package/src/oauth2/token-endpoint-auth.ts +221 -0
  143. package/src/oauth2/utils.ts +21 -5
  144. package/src/oauth2/validate-authorization-code.ts +55 -85
  145. package/src/oauth2/verify-id-token.ts +111 -0
  146. package/src/oauth2/verify.ts +82 -15
  147. package/src/social-providers/apple.ts +32 -45
  148. package/src/social-providers/atlassian.ts +20 -9
  149. package/src/social-providers/cognito.ts +51 -48
  150. package/src/social-providers/discord.ts +37 -22
  151. package/src/social-providers/dropbox.ts +20 -12
  152. package/src/social-providers/facebook.ts +108 -57
  153. package/src/social-providers/figma.ts +21 -10
  154. package/src/social-providers/github.ts +16 -10
  155. package/src/social-providers/gitlab.ts +16 -8
  156. package/src/social-providers/google.ts +67 -46
  157. package/src/social-providers/huggingface.ts +20 -9
  158. package/src/social-providers/kakao.ts +18 -9
  159. package/src/social-providers/kick.ts +20 -8
  160. package/src/social-providers/line.ts +39 -37
  161. package/src/social-providers/linear.ts +20 -7
  162. package/src/social-providers/linkedin.ts +16 -10
  163. package/src/social-providers/microsoft-entra-id.ts +66 -64
  164. package/src/social-providers/naver.ts +14 -7
  165. package/src/social-providers/notion.ts +20 -7
  166. package/src/social-providers/paybin.ts +16 -11
  167. package/src/social-providers/paypal.ts +12 -25
  168. package/src/social-providers/polar.ts +20 -9
  169. package/src/social-providers/railway.ts +20 -9
  170. package/src/social-providers/reddit.ts +22 -10
  171. package/src/social-providers/roblox.ts +31 -15
  172. package/src/social-providers/salesforce.ts +21 -10
  173. package/src/social-providers/slack.ts +31 -16
  174. package/src/social-providers/spotify.ts +20 -7
  175. package/src/social-providers/tiktok.ts +32 -13
  176. package/src/social-providers/twitch.ts +14 -9
  177. package/src/social-providers/twitter.ts +18 -8
  178. package/src/social-providers/vercel.ts +24 -11
  179. package/src/social-providers/vk.ts +20 -7
  180. package/src/social-providers/wechat.ts +28 -8
  181. package/src/social-providers/zoom.ts +28 -19
  182. package/src/types/context.ts +33 -12
  183. package/src/types/index.ts +7 -0
  184. package/src/types/init-options.ts +148 -5
  185. package/src/utils/ip.ts +12 -13
  186. package/src/utils/redirect-uri.ts +54 -0
  187. package/src/utils/string.ts +37 -0
  188. package/src/utils/url.ts +28 -0
@@ -14,11 +14,13 @@ interface SpotifyOptions extends ProviderOptions<SpotifyProfile> {
14
14
  declare const spotify: (options: SpotifyOptions) => {
15
15
  id: "spotify";
16
16
  name: string;
17
+ callbackPath: string;
17
18
  createAuthorizationURL({
18
19
  state,
19
20
  scopes,
20
21
  codeVerifier,
21
- redirectURI
22
+ redirectURI,
23
+ additionalParams
22
24
  }: {
23
25
  state: string;
24
26
  codeVerifier: string;
@@ -26,7 +28,11 @@ declare const spotify: (options: SpotifyOptions) => {
26
28
  redirectURI: string;
27
29
  display?: string | undefined;
28
30
  loginHint?: string | undefined;
29
- }): Promise<URL>;
31
+ additionalParams?: Record<string, string> | undefined;
32
+ }): Promise<{
33
+ url: URL;
34
+ requestedScopes: string[];
35
+ }>;
30
36
  validateAuthorizationCode: ({
31
37
  code,
32
38
  codeVerifier,
@@ -1,25 +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/spotify.ts
7
+ const SPOTIFY_DEFAULT_SCOPES = ["user-read-email"];
6
8
  const spotify = (options) => {
7
9
  const tokenEndpoint = "https://accounts.spotify.com/api/token";
8
10
  return {
9
11
  id: "spotify",
10
12
  name: "Spotify",
11
- createAuthorizationURL({ state, scopes, codeVerifier, redirectURI }) {
12
- const _scopes = options.disableDefaultScope ? [] : ["user-read-email"];
13
- if (options.scope) _scopes.push(...options.scope);
14
- if (scopes) _scopes.push(...scopes);
13
+ callbackPath: "/callback/spotify",
14
+ async createAuthorizationURL({ state, scopes, codeVerifier, redirectURI, additionalParams }) {
15
15
  return createAuthorizationURL({
16
16
  id: "spotify",
17
17
  options,
18
18
  authorizationEndpoint: "https://accounts.spotify.com/authorize",
19
- scopes: _scopes,
19
+ scopes: resolveRequestedScopes(options, SPOTIFY_DEFAULT_SCOPES, scopes),
20
20
  state,
21
21
  codeVerifier,
22
- redirectURI
22
+ redirectURI,
23
+ additionalParams
23
24
  });
24
25
  },
25
26
  validateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {
@@ -121,10 +121,12 @@ interface TiktokOptions extends ProviderOptions {
121
121
  declare const tiktok: (options: TiktokOptions) => {
122
122
  id: "tiktok";
123
123
  name: string;
124
+ callbackPath: string;
124
125
  createAuthorizationURL({
125
126
  state,
126
127
  scopes,
127
- redirectURI
128
+ redirectURI,
129
+ additionalParams
128
130
  }: {
129
131
  state: string;
130
132
  codeVerifier: string;
@@ -132,7 +134,11 @@ declare const tiktok: (options: TiktokOptions) => {
132
134
  redirectURI: string;
133
135
  display?: string | undefined;
134
136
  loginHint?: string | undefined;
135
- }): URL;
137
+ additionalParams?: Record<string, string> | undefined;
138
+ }): {
139
+ url: URL;
140
+ requestedScopes: string[];
141
+ };
136
142
  validateAuthorizationCode: ({
137
143
  code,
138
144
  redirectURI
@@ -1,17 +1,33 @@
1
+ import { resolveRequestedScopes } from "../oauth2/scopes.mjs";
2
+ import { RESERVED_AUTHORIZATION_PARAMS_SET } from "../oauth2/create-authorization-url.mjs";
1
3
  import { refreshAccessToken } from "../oauth2/refresh-access-token.mjs";
2
4
  import { validateAuthorizationCode } from "../oauth2/validate-authorization-code.mjs";
3
5
  import { betterFetch } from "@better-fetch/fetch";
4
6
  //#region src/social-providers/tiktok.ts
7
+ const TIKTOK_DEFAULT_SCOPES = ["user.info.profile"];
5
8
  const tiktok = (options) => {
6
9
  const tokenEndpoint = "https://open.tiktokapis.com/v2/oauth/token/";
7
10
  return {
8
11
  id: "tiktok",
9
12
  name: "TikTok",
10
- createAuthorizationURL({ state, scopes, redirectURI }) {
11
- const _scopes = options.disableDefaultScope ? [] : ["user.info.profile"];
12
- if (options.scope) _scopes.push(...options.scope);
13
- if (scopes) _scopes.push(...scopes);
14
- 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}`);
13
+ callbackPath: "/callback/tiktok",
14
+ createAuthorizationURL({ state, scopes, redirectURI, additionalParams }) {
15
+ const requestedScopes = resolveRequestedScopes(options, TIKTOK_DEFAULT_SCOPES, scopes);
16
+ const url = new URL("https://www.tiktok.com/v2/auth/authorize");
17
+ url.searchParams.set("scope", requestedScopes.join(","));
18
+ url.searchParams.set("response_type", "code");
19
+ url.searchParams.set("client_key", options.clientKey);
20
+ url.searchParams.set("redirect_uri", options.redirectURI || redirectURI);
21
+ url.searchParams.set("state", state);
22
+ if (additionalParams) for (const [key, value] of Object.entries(additionalParams)) {
23
+ if (RESERVED_AUTHORIZATION_PARAMS_SET.has(key)) continue;
24
+ if (key === "client_key") continue;
25
+ url.searchParams.set(key, value);
26
+ }
27
+ return {
28
+ url,
29
+ requestedScopes
30
+ };
15
31
  },
16
32
  validateAuthorizationCode: async ({ code, redirectURI }) => {
17
33
  return validateAuthorizationCode({
@@ -32,10 +32,12 @@ interface TwitchOptions extends ProviderOptions<TwitchProfile> {
32
32
  declare const twitch: (options: TwitchOptions) => {
33
33
  id: "twitch";
34
34
  name: string;
35
+ callbackPath: string;
35
36
  createAuthorizationURL({
36
37
  state,
37
38
  scopes,
38
- redirectURI
39
+ redirectURI,
40
+ additionalParams
39
41
  }: {
40
42
  state: string;
41
43
  codeVerifier: string;
@@ -43,7 +45,11 @@ declare const twitch: (options: TwitchOptions) => {
43
45
  redirectURI: string;
44
46
  display?: string | undefined;
45
47
  loginHint?: string | undefined;
46
- }): Promise<URL>;
48
+ additionalParams?: Record<string, string> | undefined;
49
+ }): Promise<{
50
+ url: URL;
51
+ requestedScopes: string[];
52
+ }>;
47
53
  validateAuthorizationCode: ({
48
54
  code,
49
55
  redirectURI
@@ -1,31 +1,32 @@
1
1
  import { logger } from "../env/logger.mjs";
2
+ import { resolveRequestedScopes } from "../oauth2/scopes.mjs";
2
3
  import { createAuthorizationURL } from "../oauth2/create-authorization-url.mjs";
3
4
  import { refreshAccessToken } from "../oauth2/refresh-access-token.mjs";
4
5
  import { validateAuthorizationCode } from "../oauth2/validate-authorization-code.mjs";
5
6
  import { decodeJwt } from "jose";
6
7
  //#region src/social-providers/twitch.ts
8
+ const TWITCH_DEFAULT_SCOPES = ["user:read:email", "openid"];
7
9
  const twitch = (options) => {
8
10
  const tokenEndpoint = "https://id.twitch.tv/oauth2/token";
9
11
  return {
10
12
  id: "twitch",
11
13
  name: "Twitch",
12
- createAuthorizationURL({ state, scopes, redirectURI }) {
13
- const _scopes = options.disableDefaultScope ? [] : ["user:read:email", "openid"];
14
- if (options.scope) _scopes.push(...options.scope);
15
- if (scopes) _scopes.push(...scopes);
14
+ callbackPath: "/callback/twitch",
15
+ createAuthorizationURL({ state, scopes, redirectURI, additionalParams }) {
16
16
  return createAuthorizationURL({
17
17
  id: "twitch",
18
18
  redirectURI,
19
19
  options,
20
20
  authorizationEndpoint: "https://id.twitch.tv/oauth2/authorize",
21
- scopes: _scopes,
21
+ scopes: resolveRequestedScopes(options, TWITCH_DEFAULT_SCOPES, scopes),
22
22
  state,
23
23
  claims: options.claims || [
24
24
  "email",
25
25
  "email_verified",
26
26
  "preferred_username",
27
27
  "picture"
28
- ]
28
+ ],
29
+ additionalParams
29
30
  });
30
31
  },
31
32
  validateAuthorizationCode: async ({ code, redirectURI }) => {
@@ -82,6 +82,7 @@ interface TwitterOption extends ProviderOptions<TwitterProfile> {
82
82
  declare const twitter: (options: TwitterOption) => {
83
83
  id: "twitter";
84
84
  name: string;
85
+ callbackPath: string;
85
86
  createAuthorizationURL(data: {
86
87
  state: string;
87
88
  codeVerifier: string;
@@ -89,7 +90,11 @@ declare const twitter: (options: TwitterOption) => {
89
90
  redirectURI: string;
90
91
  display?: string | undefined;
91
92
  loginHint?: string | undefined;
92
- }): Promise<URL>;
93
+ additionalParams?: Record<string, string> | undefined;
94
+ }): Promise<{
95
+ url: URL;
96
+ requestedScopes: string[];
97
+ }>;
93
98
  validateAuthorizationCode: ({
94
99
  code,
95
100
  codeVerifier,
@@ -103,7 +108,7 @@ declare const twitter: (options: TwitterOption) => {
103
108
  refreshAccessToken: (refreshToken: string) => Promise<OAuth2Tokens>;
104
109
  getUserInfo(token: OAuth2Tokens & {
105
110
  user?: {
106
- name? /** The start position (zero-based) of the recognized user's profile website. All start indices are inclusive. */: {
111
+ name?: {
107
112
  firstName?: string;
108
113
  lastName?: string;
109
114
  };
@@ -1,30 +1,31 @@
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/twitter.ts
7
+ const TWITTER_DEFAULT_SCOPES = [
8
+ "users.read",
9
+ "tweet.read",
10
+ "offline.access",
11
+ "users.email"
12
+ ];
6
13
  const twitter = (options) => {
7
14
  const tokenEndpoint = "https://api.x.com/2/oauth2/token";
8
15
  return {
9
16
  id: "twitter",
10
17
  name: "Twitter",
18
+ callbackPath: "/callback/twitter",
11
19
  createAuthorizationURL(data) {
12
- const _scopes = options.disableDefaultScope ? [] : [
13
- "users.read",
14
- "tweet.read",
15
- "offline.access",
16
- "users.email"
17
- ];
18
- if (options.scope) _scopes.push(...options.scope);
19
- if (data.scopes) _scopes.push(...data.scopes);
20
20
  return createAuthorizationURL({
21
21
  id: "twitter",
22
22
  options,
23
23
  authorizationEndpoint: "https://x.com/i/oauth2/authorize",
24
- scopes: _scopes,
24
+ scopes: resolveRequestedScopes(options, TWITTER_DEFAULT_SCOPES, data.scopes),
25
25
  state: data.state,
26
26
  codeVerifier: data.codeVerifier,
27
- redirectURI: data.redirectURI
27
+ redirectURI: data.redirectURI,
28
+ additionalParams: data.additionalParams
28
29
  });
29
30
  },
30
31
  validateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {
@@ -14,11 +14,13 @@ interface VercelOptions extends ProviderOptions<VercelProfile> {
14
14
  declare const vercel: (options: VercelOptions) => {
15
15
  id: "vercel";
16
16
  name: string;
17
+ callbackPath: string;
17
18
  createAuthorizationURL({
18
19
  state,
19
20
  scopes,
20
21
  codeVerifier,
21
- redirectURI
22
+ redirectURI,
23
+ additionalParams
22
24
  }: {
23
25
  state: string;
24
26
  codeVerifier: string;
@@ -26,7 +28,11 @@ declare const vercel: (options: VercelOptions) => {
26
28
  redirectURI: string;
27
29
  display?: string | undefined;
28
30
  loginHint?: string | undefined;
29
- }): Promise<URL>;
31
+ additionalParams?: Record<string, string> | undefined;
32
+ }): Promise<{
33
+ url: URL;
34
+ requestedScopes: string[];
35
+ }>;
30
36
  validateAuthorizationCode: ({
31
37
  code,
32
38
  codeVerifier,
@@ -1,28 +1,26 @@
1
1
  import { BetterAuthError } from "../error/index.mjs";
2
+ import { resolveRequestedScopes } from "../oauth2/scopes.mjs";
2
3
  import { createAuthorizationURL } from "../oauth2/create-authorization-url.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/vercel.ts
7
+ const VERCEL_DEFAULT_SCOPES = [];
6
8
  const vercel = (options) => {
7
9
  return {
8
10
  id: "vercel",
9
11
  name: "Vercel",
10
- createAuthorizationURL({ state, scopes, codeVerifier, redirectURI }) {
12
+ callbackPath: "/callback/vercel",
13
+ createAuthorizationURL({ state, scopes, codeVerifier, redirectURI, additionalParams }) {
11
14
  if (!codeVerifier) throw new BetterAuthError("codeVerifier is required for Vercel");
12
- let _scopes = void 0;
13
- if (options.scope !== void 0 || scopes !== void 0) {
14
- _scopes = [];
15
- if (options.scope) _scopes.push(...options.scope);
16
- if (scopes) _scopes.push(...scopes);
17
- }
18
15
  return createAuthorizationURL({
19
16
  id: "vercel",
20
17
  options,
21
18
  authorizationEndpoint: "https://vercel.com/oauth/authorize",
22
- scopes: _scopes,
19
+ scopes: resolveRequestedScopes(options, VERCEL_DEFAULT_SCOPES, scopes),
23
20
  state,
24
21
  codeVerifier,
25
- redirectURI
22
+ redirectURI,
23
+ additionalParams
26
24
  });
27
25
  },
28
26
  validateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {
@@ -20,11 +20,13 @@ interface VkOption extends ProviderOptions {
20
20
  declare const vk: (options: VkOption) => {
21
21
  id: "vk";
22
22
  name: string;
23
+ callbackPath: string;
23
24
  createAuthorizationURL({
24
25
  state,
25
26
  scopes,
26
27
  codeVerifier,
27
- redirectURI
28
+ redirectURI,
29
+ additionalParams
28
30
  }: {
29
31
  state: string;
30
32
  codeVerifier: string;
@@ -32,7 +34,11 @@ declare const vk: (options: VkOption) => {
32
34
  redirectURI: string;
33
35
  display?: string | undefined;
34
36
  loginHint?: string | undefined;
35
- }): Promise<URL>;
37
+ additionalParams?: Record<string, string> | undefined;
38
+ }): Promise<{
39
+ url: URL;
40
+ requestedScopes: string[];
41
+ }>;
36
42
  validateAuthorizationCode: ({
37
43
  code,
38
44
  codeVerifier,
@@ -1,25 +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/vk.ts
7
+ const VK_DEFAULT_SCOPES = ["email", "phone"];
6
8
  const vk = (options) => {
7
9
  const tokenEndpoint = "https://id.vk.com/oauth2/auth";
8
10
  return {
9
11
  id: "vk",
10
12
  name: "VK",
11
- async createAuthorizationURL({ state, scopes, codeVerifier, redirectURI }) {
12
- const _scopes = options.disableDefaultScope ? [] : ["email", "phone"];
13
- if (options.scope) _scopes.push(...options.scope);
14
- if (scopes) _scopes.push(...scopes);
13
+ callbackPath: "/callback/vk",
14
+ createAuthorizationURL({ state, scopes, codeVerifier, redirectURI, additionalParams }) {
15
15
  return createAuthorizationURL({
16
16
  id: "vk",
17
17
  options,
18
18
  authorizationEndpoint: "https://id.vk.com/authorize",
19
- scopes: _scopes,
19
+ scopes: resolveRequestedScopes(options, VK_DEFAULT_SCOPES, scopes),
20
20
  state,
21
21
  redirectURI,
22
- codeVerifier
22
+ codeVerifier,
23
+ additionalParams
23
24
  });
24
25
  },
25
26
  validateAuthorizationCode: async ({ code, codeVerifier, redirectURI, deviceId }) => {
@@ -53,10 +53,12 @@ interface WeChatOptions extends ProviderOptions<WeChatProfile> {
53
53
  declare const wechat: (options: WeChatOptions) => {
54
54
  id: "wechat";
55
55
  name: string;
56
+ callbackPath: string;
56
57
  createAuthorizationURL({
57
58
  state,
58
59
  scopes,
59
- redirectURI
60
+ redirectURI,
61
+ additionalParams
60
62
  }: {
61
63
  state: string;
62
64
  codeVerifier: string;
@@ -64,7 +66,11 @@ declare const wechat: (options: WeChatOptions) => {
64
66
  redirectURI: string;
65
67
  display?: string | undefined;
66
68
  loginHint?: string | undefined;
67
- }): URL;
69
+ additionalParams?: Record<string, string> | undefined;
70
+ }): {
71
+ url: URL;
72
+ requestedScopes: string[];
73
+ };
68
74
  validateAuthorizationCode: ({
69
75
  code
70
76
  }: {
@@ -1,22 +1,32 @@
1
+ import { resolveRequestedScopes } from "../oauth2/scopes.mjs";
2
+ import { RESERVED_AUTHORIZATION_PARAMS_SET } from "../oauth2/create-authorization-url.mjs";
1
3
  import { betterFetch } from "@better-fetch/fetch";
2
4
  //#region src/social-providers/wechat.ts
5
+ const WECHAT_DEFAULT_SCOPES = ["snsapi_login"];
3
6
  const wechat = (options) => {
4
7
  return {
5
8
  id: "wechat",
6
9
  name: "WeChat",
7
- createAuthorizationURL({ state, scopes, redirectURI }) {
8
- const _scopes = options.disableDefaultScope ? [] : ["snsapi_login"];
9
- options.scope && _scopes.push(...options.scope);
10
- scopes && _scopes.push(...scopes);
10
+ callbackPath: "/callback/wechat",
11
+ createAuthorizationURL({ state, scopes, redirectURI, additionalParams }) {
12
+ const requestedScopes = resolveRequestedScopes(options, WECHAT_DEFAULT_SCOPES, scopes);
11
13
  const url = new URL("https://open.weixin.qq.com/connect/qrconnect");
12
- url.searchParams.set("scope", _scopes.join(","));
14
+ url.searchParams.set("scope", requestedScopes.join(","));
13
15
  url.searchParams.set("response_type", "code");
14
16
  url.searchParams.set("appid", options.clientId);
15
17
  url.searchParams.set("redirect_uri", options.redirectURI || redirectURI);
16
18
  url.searchParams.set("state", state);
17
19
  url.searchParams.set("lang", options.lang || "cn");
20
+ if (additionalParams) for (const [key, value] of Object.entries(additionalParams)) {
21
+ if (RESERVED_AUTHORIZATION_PARAMS_SET.has(key)) continue;
22
+ if (key === "appid") continue;
23
+ url.searchParams.set(key, value);
24
+ }
18
25
  url.hash = "wechat_redirect";
19
- return url;
26
+ return {
27
+ url,
28
+ requestedScopes
29
+ };
20
30
  },
21
31
  validateAuthorizationCode: async ({ code }) => {
22
32
  const { data: tokenData, error } = await betterFetch("https://api.weixin.qq.com/sns/oauth2/access_token?" + new URLSearchParams({
@@ -116,10 +116,13 @@ interface ZoomOptions extends ProviderOptions<ZoomProfile> {
116
116
  declare const zoom: (userOptions: ZoomOptions) => {
117
117
  id: "zoom";
118
118
  name: string;
119
+ callbackPath: string;
119
120
  createAuthorizationURL: ({
120
121
  state,
122
+ scopes,
121
123
  redirectURI,
122
- codeVerifier
124
+ codeVerifier,
125
+ additionalParams
123
126
  }: {
124
127
  state: string;
125
128
  codeVerifier: string;
@@ -127,7 +130,11 @@ declare const zoom: (userOptions: ZoomOptions) => {
127
130
  redirectURI: string;
128
131
  display?: string | undefined;
129
132
  loginHint?: string | undefined;
130
- }) => Promise<URL>;
133
+ additionalParams?: Record<string, string> | undefined;
134
+ }) => Promise<{
135
+ url: URL;
136
+ requestedScopes: string[];
137
+ }>;
131
138
  validateAuthorizationCode: ({
132
139
  code,
133
140
  redirectURI,
@@ -151,7 +158,7 @@ declare const zoom: (userOptions: ZoomOptions) => {
151
158
  user: {
152
159
  id: string;
153
160
  name?: string;
154
- email /** The employee's unique ID. This field only returns when SAML single sign-on (SSO) is enabled. The `login_type` value is `101` (SSO) (Example: "HqDyI037Qjili1kNsSIrIg") */?: string | null;
161
+ email?: string | null;
155
162
  image?: string;
156
163
  emailVerified: boolean;
157
164
  [key: string]: any;
@@ -1,8 +1,10 @@
1
- import { generateCodeChallenge } from "../oauth2/utils.mjs";
1
+ import { resolveRequestedScopes } from "../oauth2/scopes.mjs";
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/zoom.ts
7
+ const ZOOM_DEFAULT_SCOPES = [];
6
8
  const zoom = (userOptions) => {
7
9
  const options = {
8
10
  pkce: true,
@@ -11,21 +13,18 @@ const zoom = (userOptions) => {
11
13
  return {
12
14
  id: "zoom",
13
15
  name: "Zoom",
14
- createAuthorizationURL: async ({ state, redirectURI, codeVerifier }) => {
15
- const params = new URLSearchParams({
16
- response_type: "code",
17
- redirect_uri: options.redirectURI ? options.redirectURI : redirectURI,
18
- client_id: options.clientId,
19
- state
16
+ callbackPath: "/callback/zoom",
17
+ createAuthorizationURL: ({ state, scopes, redirectURI, codeVerifier, additionalParams }) => {
18
+ return createAuthorizationURL({
19
+ id: "zoom",
20
+ options,
21
+ authorizationEndpoint: "https://zoom.us/oauth/authorize",
22
+ scopes: resolveRequestedScopes(options, ZOOM_DEFAULT_SCOPES, scopes),
23
+ state,
24
+ redirectURI,
25
+ codeVerifier: options.pkce ? codeVerifier : void 0,
26
+ additionalParams
20
27
  });
21
- if (options.pkce) {
22
- const codeChallenge = await generateCodeChallenge(codeVerifier);
23
- params.set("code_challenge_method", "S256");
24
- params.set("code_challenge", codeChallenge);
25
- }
26
- const url = new URL("https://zoom.us/oauth/authorize");
27
- url.search = params.toString();
28
- return url;
29
28
  },
30
29
  validateAuthorizationCode: async ({ code, redirectURI, codeVerifier }) => {
31
30
  return validateAuthorizationCode({
@@ -6,11 +6,11 @@ import { Verification } from "../db/schema/verification.mjs";
6
6
  import { createLogger } from "../env/logger.mjs";
7
7
  import { Awaitable, LiteralString } from "./helper.mjs";
8
8
  import { BetterAuthPlugin } from "./plugin.mjs";
9
- import { BetterAuthOptions, BetterAuthRateLimitOptions } from "./init-options.mjs";
9
+ import { BetterAuthOptions, BetterAuthRateLimitOptions, UserProvisioningSource } from "./init-options.mjs";
10
10
  import { Account } from "../db/schema/account.mjs";
11
11
  import { BetterAuthCookie, BetterAuthCookies } from "./cookie.mjs";
12
12
  import { SecretConfig } from "./secret.mjs";
13
- import { OAuthProvider } from "../oauth2/oauth-provider.mjs";
13
+ import { UpstreamProvider } from "../oauth2/oauth-provider.mjs";
14
14
  import { CookieOptions, EndpointContext } from "better-call";
15
15
 
16
16
  //#region src/types/context.d.ts
@@ -54,11 +54,13 @@ type GenericEndpointContext<Options extends BetterAuthOptions = BetterAuthOption
54
54
  context: AuthContext<Options>;
55
55
  };
56
56
  interface InternalAdapter<_Options extends BetterAuthOptions = BetterAuthOptions> {
57
- createOAuthUser(user: Omit<User, "id" | "createdAt" | "updatedAt">, account: Omit<Account, "userId" | "id" | "createdAt" | "updatedAt"> & Partial<Account>): Promise<{
58
- user: User;
59
- account: Account;
60
- }>;
61
- createUser<T extends Record<string, any>>(user: Omit<User, "id" | "createdAt" | "updatedAt" | "emailVerified"> & Partial<User> & Record<string, any>): Promise<T & User>;
57
+ createUser<T extends Record<string, any>>(user: Omit<User, "id" | "createdAt" | "updatedAt" | "emailVerified"> & Partial<User> & Record<string, any>,
58
+ /**
59
+ * Provisioning source. The creation seam adds `action: "create-user"` and
60
+ * runs the `user.validateUserInfo` gate.
61
+ */
62
+
63
+ source: UserProvisioningSource): Promise<T & User>;
62
64
  createAccount<T extends Record<string, any>>(account: Omit<Account, "id" | "createdAt" | "updatedAt"> & Partial<Account> & T): Promise<T & Account>;
63
65
  listSessions(userId: string, options?: {
64
66
  onlyActiveSessions?: boolean | undefined;
@@ -89,7 +91,14 @@ interface InternalAdapter<_Options extends BetterAuthOptions = BetterAuthOptions
89
91
  * @param id - The account row's primary key (the `id` column, not the `accountId` column).
90
92
  */
91
93
  deleteAccount(id: string): Promise<void>;
92
- deleteSessions(userIdOrSessionTokens: string | string[]): Promise<void>;
94
+ /**
95
+ * Delete every session belonging to a user.
96
+ */
97
+ deleteUserSessions(userId: string): Promise<void>;
98
+ /**
99
+ * Delete sessions by their session tokens.
100
+ */
101
+ deleteSessions(sessionTokens: string[]): Promise<void>;
93
102
  findOAuthUser(email: string, accountId: string, providerId: string): Promise<{
94
103
  user: User;
95
104
  linkedAccount: Account | null;
@@ -107,13 +116,26 @@ interface InternalAdapter<_Options extends BetterAuthOptions = BetterAuthOptions
107
116
  updateUserByEmail<T extends Record<string, any>>(email: string, data: Partial<User & Record<string, any>>): Promise<User & T>;
108
117
  updatePassword(userId: string, password: string): Promise<void>;
109
118
  findAccounts(userId: string): Promise<Account[]>;
110
- findAccount(accountId: string): Promise<Account | null>;
111
119
  findAccountByProviderId(accountId: string, providerId: string): Promise<Account | null>;
112
120
  findAccountByUserId(userId: string): Promise<Account[]>;
113
121
  updateAccount(id: string, data: Partial<Account>): Promise<Account>;
114
122
  createVerificationValue(data: Omit<Verification, "createdAt" | "id" | "updatedAt"> & Partial<Verification>): Promise<Verification>;
115
123
  findVerificationValue(identifier: string): Promise<Verification | null>;
116
124
  deleteVerificationByIdentifier(identifier: string): Promise<void>;
125
+ /**
126
+ * Atomically consume a single-use verification row by `identifier` and
127
+ * return it. Only the first concurrent caller receives the latest row;
128
+ * subsequent callers receive `null`. Consuming one row invalidates the
129
+ * whole identifier so stale rows cannot be replayed. Rows past their
130
+ * `expiresAt` are treated as already invalid: the row is deleted but
131
+ * `null` is returned, so callers do not need to gate on `expiresAt`
132
+ * themselves. Callers MUST gate any state change (issue session, mint
133
+ * token, change password) on a non-null result.
134
+ *
135
+ * Replaces the racy `findVerificationValue` + `deleteVerificationByIdentifier`
136
+ * pair at single-use credential consumption sites.
137
+ */
138
+ consumeVerificationValue(identifier: string): Promise<Verification | null>;
117
139
  updateVerificationByIdentifier(identifier: string, data: Partial<Verification>): Promise<Verification>;
118
140
  refreshUserSessions(user: User): Promise<void>;
119
141
  }
@@ -171,7 +193,7 @@ type AuthContext<Options extends BetterAuthOptions = BetterAuthOptions> = Plugin
171
193
  * - "cookie": Store state in an encrypted cookie (stateless)
172
194
  * - "database": Store state in the database
173
195
  *
174
- * @default "cookie"
196
+ * @default "database" when `database` or `secondaryStorage` is configured, "cookie" otherwise
175
197
  */
176
198
  storeStateStrategy: "database" | "cookie";
177
199
  };
@@ -193,7 +215,7 @@ type AuthContext<Options extends BetterAuthOptions = BetterAuthOptions> = Plugin
193
215
  session: Session & Record<string, any>;
194
216
  user: User & Record<string, any>;
195
217
  } | null) => void;
196
- socialProviders: OAuthProvider[];
218
+ socialProviders: UpstreamProvider[];
197
219
  authCookies: BetterAuthCookies;
198
220
  logger: ReturnType<typeof createLogger>;
199
221
  rateLimit: {
@@ -1,6 +1,6 @@
1
1
  import { Awaitable, AwaitableFunction, LiteralString, LiteralUnion, Prettify, Primitive, UnionToIntersection } from "./helper.mjs";
2
2
  import { BetterAuthPlugin, BetterAuthPluginErrorCodePart, HookEndpointContext } from "./plugin.mjs";
3
- import { BaseURLConfig, BetterAuthAdvancedOptions, BetterAuthDBOptions, BetterAuthOptions, BetterAuthRateLimitOptions, BetterAuthRateLimitRule, BetterAuthRateLimitStorage, DynamicBaseURLConfig, GenerateIdFn, StoreIdentifierOption } from "./init-options.mjs";
3
+ import { BaseURLConfig, BetterAuthAdvancedOptions, BetterAuthDBOptions, BetterAuthOptions, BetterAuthRateLimitOptions, BetterAuthRateLimitRule, BetterAuthRateLimitStorage, DynamicBaseURLConfig, GenerateIdFn, StoreIdentifierOption, UserProvisioningSource, ValidateUserInfoAction, ValidateUserInfoMethod, ValidateUserInfoOAuthInfo, ValidateUserInfoResult, ValidateUserInfoSSOInfo, ValidateUserInfoSource } from "./init-options.mjs";
4
4
  import { BetterAuthCookie, BetterAuthCookies } from "./cookie.mjs";
5
5
  import { SecretConfig } from "./secret.mjs";
6
6
  import { AuthContext, BetterAuthPluginRegistry, BetterAuthPluginRegistryIdentifier, GenericEndpointContext, InfoContext, InternalAdapter, PluginContext } from "./context.mjs";