@better-auth/core 1.7.0-beta.7 → 1.7.0-beta.9

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 (140) 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 +1 -1
  4. package/dist/db/get-tables.mjs +3 -3
  5. package/dist/db/schema/account.d.mts +1 -1
  6. package/dist/db/schema/account.mjs +1 -1
  7. package/dist/error/codes.d.mts +0 -5
  8. package/dist/error/codes.mjs +0 -5
  9. package/dist/instrumentation/tracer.mjs +1 -1
  10. package/dist/oauth2/create-authorization-url.d.mts +1 -4
  11. package/dist/oauth2/create-authorization-url.mjs +1 -4
  12. package/dist/oauth2/index.d.mts +3 -4
  13. package/dist/oauth2/index.mjs +2 -3
  14. package/dist/oauth2/oauth-provider.d.mts +12 -50
  15. package/dist/oauth2/refresh-access-token.mjs +2 -1
  16. package/dist/oauth2/utils.d.mts +6 -1
  17. package/dist/oauth2/utils.mjs +24 -2
  18. package/dist/oauth2/verify-id-token.d.mts +6 -5
  19. package/dist/oauth2/verify-id-token.mjs +2 -2
  20. package/dist/social-providers/apple.d.mts +1 -5
  21. package/dist/social-providers/apple.mjs +5 -5
  22. package/dist/social-providers/atlassian.d.mts +1 -5
  23. package/dist/social-providers/atlassian.mjs +4 -4
  24. package/dist/social-providers/cognito.d.mts +1 -5
  25. package/dist/social-providers/cognito.mjs +11 -18
  26. package/dist/social-providers/discord.d.mts +1 -5
  27. package/dist/social-providers/discord.mjs +6 -7
  28. package/dist/social-providers/dropbox.d.mts +1 -5
  29. package/dist/social-providers/dropbox.mjs +5 -5
  30. package/dist/social-providers/facebook.d.mts +1 -5
  31. package/dist/social-providers/facebook.mjs +5 -5
  32. package/dist/social-providers/figma.d.mts +1 -5
  33. package/dist/social-providers/figma.mjs +5 -5
  34. package/dist/social-providers/github.d.mts +1 -5
  35. package/dist/social-providers/github.mjs +4 -4
  36. package/dist/social-providers/gitlab.d.mts +1 -5
  37. package/dist/social-providers/gitlab.mjs +6 -6
  38. package/dist/social-providers/google.d.mts +8 -10
  39. package/dist/social-providers/google.mjs +12 -13
  40. package/dist/social-providers/huggingface.d.mts +1 -5
  41. package/dist/social-providers/huggingface.mjs +8 -8
  42. package/dist/social-providers/index.d.mts +35 -177
  43. package/dist/social-providers/kakao.d.mts +1 -5
  44. package/dist/social-providers/kakao.mjs +8 -8
  45. package/dist/social-providers/kick.d.mts +1 -5
  46. package/dist/social-providers/kick.mjs +4 -4
  47. package/dist/social-providers/line.d.mts +1 -5
  48. package/dist/social-providers/line.mjs +10 -10
  49. package/dist/social-providers/linear.d.mts +1 -5
  50. package/dist/social-providers/linear.mjs +4 -4
  51. package/dist/social-providers/linkedin.d.mts +1 -5
  52. package/dist/social-providers/linkedin.mjs +10 -10
  53. package/dist/social-providers/microsoft-entra-id.d.mts +1 -5
  54. package/dist/social-providers/microsoft-entra-id.mjs +10 -11
  55. package/dist/social-providers/naver.d.mts +1 -5
  56. package/dist/social-providers/naver.mjs +4 -4
  57. package/dist/social-providers/notion.d.mts +1 -5
  58. package/dist/social-providers/notion.mjs +4 -4
  59. package/dist/social-providers/paybin.d.mts +1 -5
  60. package/dist/social-providers/paybin.mjs +10 -10
  61. package/dist/social-providers/paypal.d.mts +1 -5
  62. package/dist/social-providers/paypal.mjs +2 -8
  63. package/dist/social-providers/polar.d.mts +1 -5
  64. package/dist/social-providers/polar.mjs +8 -8
  65. package/dist/social-providers/railway.d.mts +1 -5
  66. package/dist/social-providers/railway.mjs +9 -9
  67. package/dist/social-providers/reddit.d.mts +1 -5
  68. package/dist/social-providers/reddit.mjs +5 -5
  69. package/dist/social-providers/roblox.d.mts +1 -5
  70. package/dist/social-providers/roblox.mjs +5 -5
  71. package/dist/social-providers/salesforce.d.mts +1 -5
  72. package/dist/social-providers/salesforce.mjs +8 -8
  73. package/dist/social-providers/slack.d.mts +1 -5
  74. package/dist/social-providers/slack.mjs +9 -9
  75. package/dist/social-providers/spotify.d.mts +1 -5
  76. package/dist/social-providers/spotify.mjs +5 -5
  77. package/dist/social-providers/tiktok.d.mts +1 -5
  78. package/dist/social-providers/tiktok.mjs +5 -9
  79. package/dist/social-providers/twitch.d.mts +1 -5
  80. package/dist/social-providers/twitch.mjs +4 -4
  81. package/dist/social-providers/twitter.d.mts +1 -5
  82. package/dist/social-providers/twitter.mjs +9 -9
  83. package/dist/social-providers/vercel.d.mts +1 -5
  84. package/dist/social-providers/vercel.mjs +7 -4
  85. package/dist/social-providers/vk.d.mts +1 -5
  86. package/dist/social-providers/vk.mjs +5 -5
  87. package/dist/social-providers/wechat.d.mts +1 -5
  88. package/dist/social-providers/wechat.mjs +5 -9
  89. package/dist/social-providers/zoom.d.mts +1 -6
  90. package/dist/social-providers/zoom.mjs +9 -15
  91. package/dist/types/context.d.mts +6 -2
  92. package/package.json +1 -1
  93. package/src/db/get-tables.ts +3 -8
  94. package/src/db/schema/account.ts +5 -14
  95. package/src/error/codes.ts +0 -5
  96. package/src/oauth2/create-authorization-url.ts +1 -1
  97. package/src/oauth2/index.ts +2 -12
  98. package/src/oauth2/oauth-provider.ts +11 -56
  99. package/src/oauth2/refresh-access-token.ts +3 -2
  100. package/src/oauth2/utils.ts +39 -1
  101. package/src/oauth2/verify-id-token.ts +7 -5
  102. package/src/social-providers/apple.ts +8 -13
  103. package/src/social-providers/atlassian.ts +8 -12
  104. package/src/social-providers/cognito.ts +11 -18
  105. package/src/social-providers/discord.ts +8 -19
  106. package/src/social-providers/dropbox.ts +7 -13
  107. package/src/social-providers/facebook.ts +9 -13
  108. package/src/social-providers/figma.ts +9 -13
  109. package/src/social-providers/github.ts +8 -12
  110. package/src/social-providers/gitlab.ts +8 -14
  111. package/src/social-providers/google.ts +23 -29
  112. package/src/social-providers/huggingface.ts +8 -12
  113. package/src/social-providers/kakao.ts +8 -16
  114. package/src/social-providers/kick.ts +7 -12
  115. package/src/social-providers/line.ts +10 -14
  116. package/src/social-providers/linear.ts +6 -12
  117. package/src/social-providers/linkedin.ts +10 -14
  118. package/src/social-providers/microsoft-entra-id.ts +8 -18
  119. package/src/social-providers/naver.ts +6 -12
  120. package/src/social-providers/notion.ts +6 -12
  121. package/src/social-providers/paybin.ts +11 -14
  122. package/src/social-providers/paypal.ts +8 -6
  123. package/src/social-providers/polar.ts +8 -12
  124. package/src/social-providers/railway.ts +9 -13
  125. package/src/social-providers/reddit.ts +7 -18
  126. package/src/social-providers/roblox.ts +7 -18
  127. package/src/social-providers/salesforce.ts +8 -12
  128. package/src/social-providers/slack.ts +9 -18
  129. package/src/social-providers/spotify.ts +7 -13
  130. package/src/social-providers/tiktok.ts +7 -13
  131. package/src/social-providers/twitch.ts +8 -12
  132. package/src/social-providers/twitter.ts +8 -17
  133. package/src/social-providers/vercel.ts +10 -16
  134. package/src/social-providers/vk.ts +7 -13
  135. package/src/social-providers/wechat.ts +8 -20
  136. package/src/social-providers/zoom.ts +6 -19
  137. package/src/types/context.ts +8 -2
  138. package/dist/oauth2/scopes.d.mts +0 -76
  139. package/dist/oauth2/scopes.mjs +0 -96
  140. package/src/oauth2/scopes.ts +0 -118
@@ -1,9 +1,8 @@
1
1
  import { betterFetch } from "@better-fetch/fetch";
2
- import type { ProviderOptions, UpstreamProvider } from "../oauth2";
2
+ import type { OAuthProvider, ProviderOptions } from "../oauth2";
3
3
  import {
4
4
  createAuthorizationURL,
5
5
  refreshAccessToken,
6
- resolveRequestedScopes,
7
6
  validateAuthorizationCode,
8
7
  } from "../oauth2";
9
8
 
@@ -42,30 +41,22 @@ export interface SlackOptions extends ProviderOptions<SlackProfile> {
42
41
  clientId: string;
43
42
  }
44
43
 
45
- const SLACK_DEFAULT_SCOPES = ["openid", "profile", "email"];
46
-
47
44
  export const slack = (options: SlackOptions) => {
48
45
  const tokenEndpoint = "https://slack.com/api/openid.connect.token";
49
46
  return {
50
47
  id: "slack",
51
48
  name: "Slack",
52
- callbackPath: "/callback/slack",
53
- async createAuthorizationURL({
54
- state,
55
- scopes,
56
- redirectURI,
57
- additionalParams,
58
- }) {
59
- const requestedScopes = resolveRequestedScopes(
60
- options,
61
- SLACK_DEFAULT_SCOPES,
62
- scopes,
63
- );
49
+ createAuthorizationURL({ state, scopes, redirectURI, additionalParams }) {
50
+ const _scopes = options.disableDefaultScope
51
+ ? []
52
+ : ["openid", "profile", "email"];
53
+ if (scopes) _scopes.push(...scopes);
54
+ if (options.scope) _scopes.push(...options.scope);
64
55
  return createAuthorizationURL({
65
56
  id: "slack",
66
57
  options,
67
58
  authorizationEndpoint: "https://slack.com/openid/connect/authorize",
68
- scopes: requestedScopes,
59
+ scopes: _scopes,
69
60
  state,
70
61
  redirectURI,
71
62
  additionalParams,
@@ -123,5 +114,5 @@ export const slack = (options: SlackOptions) => {
123
114
  };
124
115
  },
125
116
  options,
126
- } satisfies UpstreamProvider<SlackProfile>;
117
+ } satisfies OAuthProvider<SlackProfile>;
127
118
  };
@@ -1,9 +1,8 @@
1
1
  import { betterFetch } from "@better-fetch/fetch";
2
- import type { ProviderOptions, UpstreamProvider } from "../oauth2";
2
+ import type { OAuthProvider, ProviderOptions } from "../oauth2";
3
3
  import {
4
4
  createAuthorizationURL,
5
5
  refreshAccessToken,
6
- resolveRequestedScopes,
7
6
  validateAuthorizationCode,
8
7
  } from "../oauth2";
9
8
 
@@ -20,31 +19,26 @@ export interface SpotifyOptions extends ProviderOptions<SpotifyProfile> {
20
19
  clientId: string;
21
20
  }
22
21
 
23
- const SPOTIFY_DEFAULT_SCOPES = ["user-read-email"];
24
-
25
22
  export const spotify = (options: SpotifyOptions) => {
26
23
  const tokenEndpoint = "https://accounts.spotify.com/api/token";
27
24
  return {
28
25
  id: "spotify",
29
26
  name: "Spotify",
30
- callbackPath: "/callback/spotify",
31
- async createAuthorizationURL({
27
+ createAuthorizationURL({
32
28
  state,
33
29
  scopes,
34
30
  codeVerifier,
35
31
  redirectURI,
36
32
  additionalParams,
37
33
  }) {
38
- const requestedScopes = resolveRequestedScopes(
39
- options,
40
- SPOTIFY_DEFAULT_SCOPES,
41
- scopes,
42
- );
34
+ const _scopes = options.disableDefaultScope ? [] : ["user-read-email"];
35
+ if (options.scope) _scopes.push(...options.scope);
36
+ if (scopes) _scopes.push(...scopes);
43
37
  return createAuthorizationURL({
44
38
  id: "spotify",
45
39
  options,
46
40
  authorizationEndpoint: "https://accounts.spotify.com/authorize",
47
- scopes: requestedScopes,
41
+ scopes: _scopes,
48
42
  state,
49
43
  codeVerifier,
50
44
  redirectURI,
@@ -103,5 +97,5 @@ export const spotify = (options: SpotifyOptions) => {
103
97
  };
104
98
  },
105
99
  options,
106
- } satisfies UpstreamProvider<SpotifyProfile>;
100
+ } satisfies OAuthProvider<SpotifyProfile>;
107
101
  };
@@ -1,9 +1,8 @@
1
1
  import { betterFetch } from "@better-fetch/fetch";
2
- import type { ProviderOptions, UpstreamProvider } from "../oauth2";
2
+ import type { OAuthProvider, ProviderOptions } from "../oauth2";
3
3
  import {
4
4
  RESERVED_AUTHORIZATION_PARAMS_SET,
5
5
  refreshAccessToken,
6
- resolveRequestedScopes,
7
6
  validateAuthorizationCode,
8
7
  } from "../oauth2";
9
8
 
@@ -131,24 +130,19 @@ export interface TiktokOptions extends ProviderOptions {
131
130
  clientKey: string;
132
131
  }
133
132
 
134
- const TIKTOK_DEFAULT_SCOPES = ["user.info.profile"];
135
-
136
133
  export const tiktok = (options: TiktokOptions) => {
137
134
  const tokenEndpoint = "https://open.tiktokapis.com/v2/oauth/token/";
138
135
  return {
139
136
  id: "tiktok",
140
137
  name: "TikTok",
141
- callbackPath: "/callback/tiktok",
142
138
  createAuthorizationURL({ state, scopes, redirectURI, additionalParams }) {
143
- const requestedScopes = resolveRequestedScopes(
144
- options,
145
- TIKTOK_DEFAULT_SCOPES,
146
- scopes,
147
- );
139
+ const _scopes = options.disableDefaultScope ? [] : ["user.info.profile"];
140
+ if (options.scope) _scopes.push(...options.scope);
141
+ if (scopes) _scopes.push(...scopes);
148
142
  // TikTok uses `client_key` instead of the standard `client_id`, so the
149
143
  // shared createAuthorizationURL helper cannot be used directly.
150
144
  const url = new URL("https://www.tiktok.com/v2/auth/authorize");
151
- url.searchParams.set("scope", requestedScopes.join(","));
145
+ url.searchParams.set("scope", _scopes.join(","));
152
146
  url.searchParams.set("response_type", "code");
153
147
  url.searchParams.set("client_key", options.clientKey);
154
148
  url.searchParams.set("redirect_uri", options.redirectURI || redirectURI);
@@ -160,7 +154,7 @@ export const tiktok = (options: TiktokOptions) => {
160
154
  url.searchParams.set(key, value);
161
155
  }
162
156
  }
163
- return { url, requestedScopes };
157
+ return url;
164
158
  },
165
159
 
166
160
  validateAuthorizationCode: async ({ code, redirectURI }) => {
@@ -226,5 +220,5 @@ export const tiktok = (options: TiktokOptions) => {
226
220
  };
227
221
  },
228
222
  options,
229
- } satisfies UpstreamProvider<TiktokProfile, TiktokOptions>;
223
+ } satisfies OAuthProvider<TiktokProfile, TiktokOptions>;
230
224
  };
@@ -1,10 +1,9 @@
1
1
  import { decodeJwt } from "jose";
2
2
  import { logger } from "../env";
3
- import type { ProviderOptions, UpstreamProvider } from "../oauth2";
3
+ import type { OAuthProvider, ProviderOptions } from "../oauth2";
4
4
  import {
5
5
  createAuthorizationURL,
6
6
  refreshAccessToken,
7
- resolveRequestedScopes,
8
7
  validateAuthorizationCode,
9
8
  } from "../oauth2";
10
9
 
@@ -38,26 +37,23 @@ export interface TwitchOptions extends ProviderOptions<TwitchProfile> {
38
37
  clientId: string;
39
38
  claims?: string[] | undefined;
40
39
  }
41
- const TWITCH_DEFAULT_SCOPES = ["user:read:email", "openid"];
42
-
43
40
  export const twitch = (options: TwitchOptions) => {
44
41
  const tokenEndpoint = "https://id.twitch.tv/oauth2/token";
45
42
  return {
46
43
  id: "twitch",
47
44
  name: "Twitch",
48
- callbackPath: "/callback/twitch",
49
45
  createAuthorizationURL({ state, scopes, redirectURI, additionalParams }) {
50
- const requestedScopes = resolveRequestedScopes(
51
- options,
52
- TWITCH_DEFAULT_SCOPES,
53
- scopes,
54
- );
46
+ const _scopes = options.disableDefaultScope
47
+ ? []
48
+ : ["user:read:email", "openid"];
49
+ if (options.scope) _scopes.push(...options.scope);
50
+ if (scopes) _scopes.push(...scopes);
55
51
  return createAuthorizationURL({
56
52
  id: "twitch",
57
53
  redirectURI,
58
54
  options,
59
55
  authorizationEndpoint: "https://id.twitch.tv/oauth2/authorize",
60
- scopes: requestedScopes,
56
+ scopes: _scopes,
61
57
  state,
62
58
  claims: options.claims || [
63
59
  "email",
@@ -113,5 +109,5 @@ export const twitch = (options: TwitchOptions) => {
113
109
  };
114
110
  },
115
111
  options,
116
- } satisfies UpstreamProvider<TwitchProfile>;
112
+ } satisfies OAuthProvider<TwitchProfile>;
117
113
  };
@@ -1,9 +1,8 @@
1
1
  import { betterFetch } from "@better-fetch/fetch";
2
- import type { ProviderOptions, UpstreamProvider } from "../oauth2";
2
+ import type { OAuthProvider, ProviderOptions } from "../oauth2";
3
3
  import {
4
4
  createAuthorizationURL,
5
5
  refreshAccessToken,
6
- resolveRequestedScopes,
7
6
  validateAuthorizationCode,
8
7
  } from "../oauth2";
9
8
 
@@ -104,30 +103,22 @@ export interface TwitterOption extends ProviderOptions<TwitterProfile> {
104
103
  clientId: string;
105
104
  }
106
105
 
107
- const TWITTER_DEFAULT_SCOPES = [
108
- "users.read",
109
- "tweet.read",
110
- "offline.access",
111
- "users.email",
112
- ];
113
-
114
106
  export const twitter = (options: TwitterOption) => {
115
107
  const tokenEndpoint = "https://api.x.com/2/oauth2/token";
116
108
  return {
117
109
  id: "twitter",
118
110
  name: "Twitter",
119
- callbackPath: "/callback/twitter",
120
111
  createAuthorizationURL(data) {
121
- const requestedScopes = resolveRequestedScopes(
122
- options,
123
- TWITTER_DEFAULT_SCOPES,
124
- data.scopes,
125
- );
112
+ const _scopes = options.disableDefaultScope
113
+ ? []
114
+ : ["users.read", "tweet.read", "offline.access", "users.email"];
115
+ if (options.scope) _scopes.push(...options.scope);
116
+ if (data.scopes) _scopes.push(...data.scopes);
126
117
  return createAuthorizationURL({
127
118
  id: "twitter",
128
119
  options,
129
120
  authorizationEndpoint: "https://x.com/i/oauth2/authorize",
130
- scopes: requestedScopes,
121
+ scopes: _scopes,
131
122
  state: data.state,
132
123
  codeVerifier: data.codeVerifier,
133
124
  redirectURI: data.redirectURI,
@@ -205,5 +196,5 @@ export const twitter = (options: TwitterOption) => {
205
196
  };
206
197
  },
207
198
  options,
208
- } satisfies UpstreamProvider<TwitterProfile>;
199
+ } satisfies OAuthProvider<TwitterProfile>;
209
200
  };
@@ -1,11 +1,7 @@
1
1
  import { betterFetch } from "@better-fetch/fetch";
2
2
  import { BetterAuthError } from "../error";
3
- import type { ProviderOptions, UpstreamProvider } from "../oauth2";
4
- import {
5
- createAuthorizationURL,
6
- resolveRequestedScopes,
7
- validateAuthorizationCode,
8
- } from "../oauth2";
3
+ import type { OAuthProvider, ProviderOptions } from "../oauth2";
4
+ import { createAuthorizationURL, validateAuthorizationCode } from "../oauth2";
9
5
 
10
6
  export interface VercelProfile {
11
7
  sub: string;
@@ -20,13 +16,10 @@ export interface VercelOptions extends ProviderOptions<VercelProfile> {
20
16
  clientId: string;
21
17
  }
22
18
 
23
- const VERCEL_DEFAULT_SCOPES: string[] = [];
24
-
25
19
  export const vercel = (options: VercelOptions) => {
26
20
  return {
27
21
  id: "vercel",
28
22
  name: "Vercel",
29
- callbackPath: "/callback/vercel",
30
23
  createAuthorizationURL({
31
24
  state,
32
25
  scopes,
@@ -38,17 +31,18 @@ export const vercel = (options: VercelOptions) => {
38
31
  throw new BetterAuthError("codeVerifier is required for Vercel");
39
32
  }
40
33
 
41
- const requestedScopes = resolveRequestedScopes(
42
- options,
43
- VERCEL_DEFAULT_SCOPES,
44
- scopes,
45
- );
34
+ let _scopes: string[] | undefined = undefined;
35
+ if (options.scope !== undefined || scopes !== undefined) {
36
+ _scopes = [];
37
+ if (options.scope) _scopes.push(...options.scope);
38
+ if (scopes) _scopes.push(...scopes);
39
+ }
46
40
 
47
41
  return createAuthorizationURL({
48
42
  id: "vercel",
49
43
  options,
50
44
  authorizationEndpoint: "https://vercel.com/oauth/authorize",
51
- scopes: requestedScopes,
45
+ scopes: _scopes,
52
46
  state,
53
47
  codeVerifier,
54
48
  redirectURI,
@@ -96,5 +90,5 @@ export const vercel = (options: VercelOptions) => {
96
90
  };
97
91
  },
98
92
  options,
99
- } satisfies UpstreamProvider<VercelProfile>;
93
+ } satisfies OAuthProvider<VercelProfile>;
100
94
  };
@@ -1,9 +1,8 @@
1
1
  import { betterFetch } from "@better-fetch/fetch";
2
- import type { ProviderOptions, UpstreamProvider } from "../oauth2";
2
+ import type { OAuthProvider, ProviderOptions } from "../oauth2";
3
3
  import {
4
4
  createAuthorizationURL,
5
5
  refreshAccessToken,
6
- resolveRequestedScopes,
7
6
  validateAuthorizationCode,
8
7
  } from "../oauth2";
9
8
 
@@ -26,33 +25,28 @@ export interface VkOption extends ProviderOptions {
26
25
  scheme?: ("light" | "dark") | undefined;
27
26
  }
28
27
 
29
- const VK_DEFAULT_SCOPES = ["email", "phone"];
30
-
31
28
  export const vk = (options: VkOption) => {
32
29
  const tokenEndpoint = "https://id.vk.com/oauth2/auth";
33
30
  return {
34
31
  id: "vk",
35
32
  name: "VK",
36
- callbackPath: "/callback/vk",
37
- createAuthorizationURL({
33
+ async createAuthorizationURL({
38
34
  state,
39
35
  scopes,
40
36
  codeVerifier,
41
37
  redirectURI,
42
38
  additionalParams,
43
39
  }) {
44
- const requestedScopes = resolveRequestedScopes(
45
- options,
46
- VK_DEFAULT_SCOPES,
47
- scopes,
48
- );
40
+ const _scopes = options.disableDefaultScope ? [] : ["email", "phone"];
41
+ if (options.scope) _scopes.push(...options.scope);
42
+ if (scopes) _scopes.push(...scopes);
49
43
  const authorizationEndpoint = "https://id.vk.com/authorize";
50
44
 
51
45
  return createAuthorizationURL({
52
46
  id: "vk",
53
47
  options,
54
48
  authorizationEndpoint,
55
- scopes: requestedScopes,
49
+ scopes: _scopes,
56
50
  state,
57
51
  redirectURI,
58
52
  codeVerifier,
@@ -134,5 +128,5 @@ export const vk = (options: VkOption) => {
134
128
  };
135
129
  },
136
130
  options,
137
- } satisfies UpstreamProvider<VkProfile>;
131
+ } satisfies OAuthProvider<VkProfile>;
138
132
  };
@@ -1,13 +1,6 @@
1
1
  import { betterFetch } from "@better-fetch/fetch";
2
- import type {
3
- OAuth2Tokens,
4
- ProviderOptions,
5
- UpstreamProvider,
6
- } from "../oauth2";
7
- import {
8
- RESERVED_AUTHORIZATION_PARAMS_SET,
9
- resolveRequestedScopes,
10
- } from "../oauth2";
2
+ import type { OAuth2Tokens, OAuthProvider, ProviderOptions } from "../oauth2";
3
+ import { RESERVED_AUTHORIZATION_PARAMS_SET } from "../oauth2";
11
4
 
12
5
  /**
13
6
  * WeChat user profile information
@@ -62,24 +55,19 @@ export interface WeChatOptions extends ProviderOptions<WeChatProfile> {
62
55
  lang?: "cn" | "en";
63
56
  }
64
57
 
65
- const WECHAT_DEFAULT_SCOPES = ["snsapi_login"];
66
-
67
58
  export const wechat = (options: WeChatOptions) => {
68
59
  return {
69
60
  id: "wechat",
70
61
  name: "WeChat",
71
- callbackPath: "/callback/wechat",
72
62
  createAuthorizationURL({ state, scopes, redirectURI, additionalParams }) {
73
- const requestedScopes = resolveRequestedScopes(
74
- options,
75
- WECHAT_DEFAULT_SCOPES,
76
- scopes,
77
- );
63
+ const _scopes = options.disableDefaultScope ? [] : ["snsapi_login"];
64
+ options.scope && _scopes.push(...options.scope);
65
+ scopes && _scopes.push(...scopes);
78
66
 
79
67
  // WeChat uses non-standard OAuth2 parameters (appid instead of client_id)
80
68
  // and requires a fragment (#wechat_redirect), so we construct the URL manually.
81
69
  const url = new URL("https://open.weixin.qq.com/connect/qrconnect");
82
- url.searchParams.set("scope", requestedScopes.join(","));
70
+ url.searchParams.set("scope", _scopes.join(","));
83
71
  url.searchParams.set("response_type", "code");
84
72
  url.searchParams.set("appid", options.clientId);
85
73
  url.searchParams.set("redirect_uri", options.redirectURI || redirectURI);
@@ -94,7 +82,7 @@ export const wechat = (options: WeChatOptions) => {
94
82
  }
95
83
  url.hash = "wechat_redirect";
96
84
 
97
- return { url, requestedScopes };
85
+ return url;
98
86
  },
99
87
 
100
88
  // WeChat uses non-standard token exchange (appid/secret instead of
@@ -236,5 +224,5 @@ export const wechat = (options: WeChatOptions) => {
236
224
  };
237
225
  },
238
226
  options,
239
- } satisfies UpstreamProvider<WeChatProfile, WeChatOptions>;
227
+ } satisfies OAuthProvider<WeChatProfile, WeChatOptions>;
240
228
  };
@@ -1,9 +1,8 @@
1
1
  import { betterFetch } from "@better-fetch/fetch";
2
- import type { ProviderOptions, UpstreamProvider } from "../oauth2";
2
+ import type { OAuthProvider, ProviderOptions } from "../oauth2";
3
3
  import {
4
4
  createAuthorizationURL,
5
5
  refreshAccessToken,
6
- resolveRequestedScopes,
7
6
  validateAuthorizationCode,
8
7
  } from "../oauth2";
9
8
 
@@ -144,8 +143,6 @@ export interface ZoomOptions extends ProviderOptions<ZoomProfile> {
144
143
  pkce?: boolean | undefined;
145
144
  }
146
145
 
147
- const ZOOM_DEFAULT_SCOPES: string[] = [];
148
-
149
146
  export const zoom = (userOptions: ZoomOptions) => {
150
147
  const options = {
151
148
  pkce: true,
@@ -155,31 +152,21 @@ export const zoom = (userOptions: ZoomOptions) => {
155
152
  return {
156
153
  id: "zoom",
157
154
  name: "Zoom",
158
- callbackPath: "/callback/zoom",
159
- createAuthorizationURL: ({
155
+ createAuthorizationURL: async ({
160
156
  state,
161
- scopes,
162
157
  redirectURI,
163
158
  codeVerifier,
164
159
  additionalParams,
165
- }) => {
166
- const requestedScopes = resolveRequestedScopes(
167
- options,
168
- ZOOM_DEFAULT_SCOPES,
169
- scopes,
170
- );
171
-
172
- return createAuthorizationURL({
160
+ }) =>
161
+ createAuthorizationURL({
173
162
  id: "zoom",
174
163
  options,
175
164
  authorizationEndpoint: "https://zoom.us/oauth/authorize",
176
- scopes: requestedScopes,
177
165
  state,
178
166
  redirectURI,
179
167
  codeVerifier: options.pkce ? codeVerifier : undefined,
180
168
  additionalParams,
181
- });
182
- },
169
+ }),
183
170
  validateAuthorizationCode: async ({ code, redirectURI, codeVerifier }) => {
184
171
  return validateAuthorizationCode({
185
172
  code,
@@ -235,5 +222,5 @@ export const zoom = (userOptions: ZoomOptions) => {
235
222
  },
236
223
  };
237
224
  },
238
- } satisfies UpstreamProvider<ZoomProfile>;
225
+ } satisfies OAuthProvider<ZoomProfile>;
239
226
  };
@@ -10,7 +10,7 @@ import type {
10
10
  } from "../db";
11
11
  import type { DBAdapter, Where } from "../db/adapter";
12
12
  import type { createLogger } from "../env";
13
- import type { UpstreamProvider } from "../oauth2";
13
+ import type { OAuthProvider } from "../oauth2";
14
14
  import type { BetterAuthCookie, BetterAuthCookies } from "./cookie";
15
15
  import type { Awaitable, LiteralString } from "./helper";
16
16
  import type {
@@ -88,6 +88,12 @@ export type GenericEndpointContext<
88
88
  export interface InternalAdapter<
89
89
  _Options extends BetterAuthOptions = BetterAuthOptions,
90
90
  > {
91
+ createOAuthUser(
92
+ user: Omit<User, "id" | "createdAt" | "updatedAt">,
93
+ account: Omit<Account, "userId" | "id" | "createdAt" | "updatedAt"> &
94
+ Partial<Account>,
95
+ ): Promise<{ user: User; account: Account }>;
96
+
91
97
  createUser<T extends Record<string, any>>(
92
98
  user: Omit<User, "id" | "createdAt" | "updatedAt" | "emailVerified"> &
93
99
  Partial<User> &
@@ -369,7 +375,7 @@ export type AuthContext<Options extends BetterAuthOptions = BetterAuthOptions> =
369
375
  user: User & Record<string, any>;
370
376
  } | null,
371
377
  ) => void;
372
- socialProviders: UpstreamProvider[];
378
+ socialProviders: OAuthProvider[];
373
379
  authCookies: BetterAuthCookies;
374
380
  logger: ReturnType<typeof createLogger>;
375
381
  rateLimit: {
@@ -1,76 +0,0 @@
1
- import { ProviderOptions } from "./oauth-provider.mjs";
2
-
3
- //#region src/oauth2/scopes.d.ts
4
- /**
5
- * Parse a provider's `scope` token-response field into a string array.
6
- *
7
- * RFC 6749 §3.3 defines `scope` as a space-delimited string, but providers
8
- * vary: some (e.g. Twitch) return an already-split array. Accept both, plus the
9
- * omitted/empty case, without ever calling `.split` on a non-string. Returns
10
- * `[]` when no scope is present.
11
- *
12
- * @see https://github.com/better-auth/better-auth/issues/9076
13
- */
14
- declare function parseScopeField(scope: unknown): string[];
15
- /**
16
- * Normalize a scope set into a single deduped, sorted array.
17
- *
18
- * Scope order is insignificant per RFC 6749 §3.3, so normalize for idempotent
19
- * writes and trivial comparisons: trim each token, drop empties, dedupe, and
20
- * sort ascending. Returns `[]` when the union is empty.
21
- *
22
- * @see https://www.rfc-editor.org/rfc/rfc6749#section-3.3
23
- */
24
- declare function normalizeScopes(stored: string[] | null | undefined, incoming?: string[] | undefined): string[];
25
- /**
26
- * Union the stored granted-scope set with the scopes observed on an
27
- * authorization or token exchange.
28
- *
29
- * The provider's echoed `scope` is authoritative when present. RFC 6749 §3.3
30
- * and §5.1 say an omitted or empty echo means the grant equals what was
31
- * requested, so fall back to `requested` in that case. The result unions onto
32
- * the stored grant (never narrows on a normal write) and is normalized per
33
- * {@link normalizeScopes}.
34
- *
35
- * @see https://www.rfc-editor.org/rfc/rfc6749#section-3.3
36
- * @see https://www.rfc-editor.org/rfc/rfc6749#section-5.1
37
- */
38
- declare function unionGrantedScopes(stored: string[] | null | undefined, echoed: string[] | undefined, requested: string[] | undefined): string[];
39
- /**
40
- * Coerce a stored granted-scope value into a usable array.
41
- *
42
- * `account.grantedScopes` is nullable (legacy rows and non-OAuth accounts read
43
- * as unset), and on dialects that store the array as a JSON string a malformed
44
- * operator backfill could deserialize to a non-array. Both collapse to `[]`
45
- * here so every reader works against a real `string[]` without re-deriving the
46
- * guard.
47
- */
48
- declare function readGrantedScopes(stored: string[] | null | undefined): string[];
49
- /**
50
- * Test whether a normalized granted-scope set contains a specific scope.
51
- *
52
- * Matching is exact and case-sensitive per RFC 6749 §3.3. The argument is the
53
- * normalized `account.grantedScopes` array; a raw provider `scope` string must
54
- * be run through {@link parseScopeField} first.
55
- *
56
- * @see https://www.rfc-editor.org/rfc/rfc6749#section-3.3
57
- */
58
- declare function includesGrantedScope(granted: string[] | null | undefined, scope: string): boolean;
59
- /**
60
- * Compose the effective scope set to encode in a single authorization URL.
61
- *
62
- * Precedence: the provider's built-in defaults (unless `disableDefaultScope`),
63
- * then the integrator's configured `options.scope`, then the per-request
64
- * `scopes`. The result is the value persisted into OAuth state as the RFC 6749
65
- * §5.1 fallback, so it is preserved verbatim (not normalized) to match what is
66
- * sent to the provider.
67
- *
68
- * `defaultScopes` is a parameter rather than a provider-contract field so the
69
- * runtime-synthesized generic OAuth provider, which has no static default set,
70
- * can pass its configured scopes here.
71
- *
72
- * @see https://www.rfc-editor.org/rfc/rfc6749#section-5.1
73
- */
74
- declare function resolveRequestedScopes(options: Pick<ProviderOptions, "scope" | "disableDefaultScope"> | undefined, defaultScopes: string[], perRequestScopes: string[] | undefined): string[];
75
- //#endregion
76
- export { includesGrantedScope, normalizeScopes, parseScopeField, readGrantedScopes, resolveRequestedScopes, unionGrantedScopes };