@better-auth/core 1.7.0-beta.4 → 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 (150) 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 +2 -2
  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/env/env-impl.mjs +1 -1
  8. package/dist/error/codes.d.mts +5 -0
  9. package/dist/error/codes.mjs +5 -0
  10. package/dist/index.d.mts +2 -2
  11. package/dist/instrumentation/tracer.mjs +1 -1
  12. package/dist/oauth2/create-authorization-url.d.mts +4 -1
  13. package/dist/oauth2/create-authorization-url.mjs +5 -2
  14. package/dist/oauth2/index.d.mts +4 -2
  15. package/dist/oauth2/index.mjs +3 -1
  16. package/dist/oauth2/oauth-provider.d.mts +128 -9
  17. package/dist/oauth2/refresh-access-token.mjs +1 -1
  18. package/dist/oauth2/scopes.d.mts +76 -0
  19. package/dist/oauth2/scopes.mjs +96 -0
  20. package/dist/oauth2/utils.mjs +2 -1
  21. package/dist/oauth2/verify-id-token.d.mts +26 -0
  22. package/dist/oauth2/verify-id-token.mjs +62 -0
  23. package/dist/oauth2/verify.d.mts +14 -0
  24. package/dist/oauth2/verify.mjs +23 -7
  25. package/dist/social-providers/apple.d.mts +14 -2
  26. package/dist/social-providers/apple.mjs +12 -36
  27. package/dist/social-providers/atlassian.d.mts +5 -1
  28. package/dist/social-providers/atlassian.mjs +4 -4
  29. package/dist/social-providers/cognito.d.mts +13 -2
  30. package/dist/social-providers/cognito.mjs +24 -32
  31. package/dist/social-providers/discord.d.mts +5 -1
  32. package/dist/social-providers/discord.mjs +7 -6
  33. package/dist/social-providers/dropbox.d.mts +5 -1
  34. package/dist/social-providers/dropbox.mjs +5 -5
  35. package/dist/social-providers/facebook.d.mts +21 -2
  36. package/dist/social-providers/facebook.mjs +46 -22
  37. package/dist/social-providers/figma.d.mts +5 -1
  38. package/dist/social-providers/figma.mjs +5 -5
  39. package/dist/social-providers/github.d.mts +5 -1
  40. package/dist/social-providers/github.mjs +4 -4
  41. package/dist/social-providers/gitlab.d.mts +5 -1
  42. package/dist/social-providers/gitlab.mjs +6 -6
  43. package/dist/social-providers/google.d.mts +29 -3
  44. package/dist/social-providers/google.mjs +24 -30
  45. package/dist/social-providers/huggingface.d.mts +5 -1
  46. package/dist/social-providers/huggingface.mjs +8 -8
  47. package/dist/social-providers/index.d.mts +221 -42
  48. package/dist/social-providers/kakao.d.mts +5 -1
  49. package/dist/social-providers/kakao.mjs +8 -8
  50. package/dist/social-providers/kick.d.mts +5 -1
  51. package/dist/social-providers/kick.mjs +4 -4
  52. package/dist/social-providers/line.d.mts +8 -2
  53. package/dist/social-providers/line.mjs +12 -14
  54. package/dist/social-providers/linear.d.mts +5 -1
  55. package/dist/social-providers/linear.mjs +4 -4
  56. package/dist/social-providers/linkedin.d.mts +5 -1
  57. package/dist/social-providers/linkedin.mjs +10 -10
  58. package/dist/social-providers/microsoft-entra-id.d.mts +31 -6
  59. package/dist/social-providers/microsoft-entra-id.mjs +26 -37
  60. package/dist/social-providers/naver.d.mts +5 -1
  61. package/dist/social-providers/naver.mjs +4 -4
  62. package/dist/social-providers/notion.d.mts +5 -1
  63. package/dist/social-providers/notion.mjs +4 -4
  64. package/dist/social-providers/paybin.d.mts +5 -1
  65. package/dist/social-providers/paybin.mjs +10 -10
  66. package/dist/social-providers/paypal.d.mts +5 -2
  67. package/dist/social-providers/paypal.mjs +8 -13
  68. package/dist/social-providers/polar.d.mts +5 -1
  69. package/dist/social-providers/polar.mjs +8 -8
  70. package/dist/social-providers/railway.d.mts +5 -1
  71. package/dist/social-providers/railway.mjs +9 -9
  72. package/dist/social-providers/reddit.d.mts +5 -1
  73. package/dist/social-providers/reddit.mjs +9 -8
  74. package/dist/social-providers/roblox.d.mts +5 -1
  75. package/dist/social-providers/roblox.mjs +5 -5
  76. package/dist/social-providers/salesforce.d.mts +5 -1
  77. package/dist/social-providers/salesforce.mjs +8 -8
  78. package/dist/social-providers/slack.d.mts +5 -1
  79. package/dist/social-providers/slack.mjs +9 -9
  80. package/dist/social-providers/spotify.d.mts +5 -1
  81. package/dist/social-providers/spotify.mjs +5 -5
  82. package/dist/social-providers/tiktok.d.mts +5 -1
  83. package/dist/social-providers/tiktok.mjs +9 -5
  84. package/dist/social-providers/twitch.d.mts +5 -1
  85. package/dist/social-providers/twitch.mjs +4 -4
  86. package/dist/social-providers/twitter.d.mts +6 -4
  87. package/dist/social-providers/twitter.mjs +9 -9
  88. package/dist/social-providers/vercel.d.mts +5 -1
  89. package/dist/social-providers/vercel.mjs +4 -7
  90. package/dist/social-providers/vk.d.mts +5 -1
  91. package/dist/social-providers/vk.mjs +5 -5
  92. package/dist/social-providers/wechat.d.mts +5 -1
  93. package/dist/social-providers/wechat.mjs +9 -5
  94. package/dist/social-providers/zoom.d.mts +6 -1
  95. package/dist/social-providers/zoom.mjs +15 -9
  96. package/dist/types/context.d.mts +10 -8
  97. package/dist/types/index.d.mts +1 -1
  98. package/dist/types/init-options.d.mts +92 -1
  99. package/package.json +5 -5
  100. package/src/db/adapter/factory.ts +10 -2
  101. package/src/db/get-tables.ts +8 -3
  102. package/src/db/schema/account.ts +14 -2
  103. package/src/env/env-impl.ts +1 -2
  104. package/src/error/codes.ts +5 -0
  105. package/src/oauth2/create-authorization-url.ts +2 -2
  106. package/src/oauth2/index.ts +17 -1
  107. package/src/oauth2/oauth-provider.ts +140 -10
  108. package/src/oauth2/refresh-access-token.ts +2 -2
  109. package/src/oauth2/scopes.ts +118 -0
  110. package/src/oauth2/utils.ts +2 -5
  111. package/src/oauth2/verify-id-token.ts +111 -0
  112. package/src/oauth2/verify.ts +62 -11
  113. package/src/social-providers/apple.ts +24 -61
  114. package/src/social-providers/atlassian.ts +12 -8
  115. package/src/social-providers/cognito.ts +25 -47
  116. package/src/social-providers/discord.ts +19 -8
  117. package/src/social-providers/dropbox.ts +13 -7
  118. package/src/social-providers/facebook.ts +97 -51
  119. package/src/social-providers/figma.ts +13 -9
  120. package/src/social-providers/github.ts +12 -8
  121. package/src/social-providers/gitlab.ts +14 -8
  122. package/src/social-providers/google.ts +66 -47
  123. package/src/social-providers/huggingface.ts +12 -8
  124. package/src/social-providers/kakao.ts +16 -8
  125. package/src/social-providers/kick.ts +12 -7
  126. package/src/social-providers/line.ts +37 -37
  127. package/src/social-providers/linear.ts +12 -6
  128. package/src/social-providers/linkedin.ts +14 -10
  129. package/src/social-providers/microsoft-entra-id.ts +65 -64
  130. package/src/social-providers/naver.ts +12 -6
  131. package/src/social-providers/notion.ts +12 -6
  132. package/src/social-providers/paybin.ts +14 -11
  133. package/src/social-providers/paypal.ts +6 -25
  134. package/src/social-providers/polar.ts +12 -8
  135. package/src/social-providers/railway.ts +13 -9
  136. package/src/social-providers/reddit.ts +21 -10
  137. package/src/social-providers/roblox.ts +18 -7
  138. package/src/social-providers/salesforce.ts +12 -8
  139. package/src/social-providers/slack.ts +18 -9
  140. package/src/social-providers/spotify.ts +13 -7
  141. package/src/social-providers/tiktok.ts +13 -7
  142. package/src/social-providers/twitch.ts +12 -8
  143. package/src/social-providers/twitter.ts +17 -8
  144. package/src/social-providers/vercel.ts +16 -10
  145. package/src/social-providers/vk.ts +13 -7
  146. package/src/social-providers/wechat.ts +20 -8
  147. package/src/social-providers/zoom.ts +19 -6
  148. package/src/types/context.ts +8 -8
  149. package/src/types/index.ts +7 -0
  150. package/src/types/init-options.ts +119 -0
@@ -93,6 +93,7 @@ interface KakaoOptions extends ProviderOptions<KakaoProfile> {
93
93
  declare const kakao: (options: KakaoOptions) => {
94
94
  id: "kakao";
95
95
  name: string;
96
+ callbackPath: string;
96
97
  createAuthorizationURL({
97
98
  state,
98
99
  scopes,
@@ -106,7 +107,10 @@ declare const kakao: (options: KakaoOptions) => {
106
107
  display?: string | undefined;
107
108
  loginHint?: string | undefined;
108
109
  additionalParams?: Record<string, string> | undefined;
109
- }): Promise<URL>;
110
+ }): Promise<{
111
+ url: URL;
112
+ requestedScopes: string[];
113
+ }>;
110
114
  validateAuthorizationCode: ({
111
115
  code,
112
116
  redirectURI
@@ -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/kakao.ts
7
+ const KAKAO_DEFAULT_SCOPES = [
8
+ "account_email",
9
+ "profile_image",
10
+ "profile_nickname"
11
+ ];
6
12
  const kakao = (options) => {
7
13
  const tokenEndpoint = "https://kauth.kakao.com/oauth/token";
8
14
  return {
9
15
  id: "kakao",
10
16
  name: "Kakao",
17
+ callbackPath: "/callback/kakao",
11
18
  createAuthorizationURL({ state, scopes, redirectURI, additionalParams }) {
12
- const _scopes = options.disableDefaultScope ? [] : [
13
- "account_email",
14
- "profile_image",
15
- "profile_nickname"
16
- ];
17
- if (options.scope) _scopes.push(...options.scope);
18
- if (scopes) _scopes.push(...scopes);
19
19
  return createAuthorizationURL({
20
20
  id: "kakao",
21
21
  options,
22
22
  authorizationEndpoint: "https://kauth.kakao.com/oauth/authorize",
23
- scopes: _scopes,
23
+ scopes: resolveRequestedScopes(options, KAKAO_DEFAULT_SCOPES, scopes),
24
24
  state,
25
25
  redirectURI,
26
26
  additionalParams
@@ -24,6 +24,7 @@ interface KickOptions extends ProviderOptions<KickProfile> {
24
24
  declare const kick: (options: KickOptions) => {
25
25
  id: "kick";
26
26
  name: string;
27
+ callbackPath: string;
27
28
  createAuthorizationURL({
28
29
  state,
29
30
  scopes,
@@ -38,7 +39,10 @@ declare const kick: (options: KickOptions) => {
38
39
  display?: string | undefined;
39
40
  loginHint?: string | undefined;
40
41
  additionalParams?: Record<string, string> | undefined;
41
- }): Promise<URL>;
42
+ }): Promise<{
43
+ url: URL;
44
+ requestedScopes: string[];
45
+ }>;
42
46
  validateAuthorizationCode({
43
47
  code,
44
48
  redirectURI,
@@ -1,22 +1,22 @@
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/kick.ts
7
+ const KICK_DEFAULT_SCOPES = ["user:read"];
6
8
  const kick = (options) => {
7
9
  return {
8
10
  id: "kick",
9
11
  name: "Kick",
12
+ callbackPath: "/callback/kick",
10
13
  createAuthorizationURL({ state, scopes, redirectURI, codeVerifier, additionalParams }) {
11
- const _scopes = options.disableDefaultScope ? [] : ["user:read"];
12
- if (options.scope) _scopes.push(...options.scope);
13
- if (scopes) _scopes.push(...scopes);
14
14
  return createAuthorizationURL({
15
15
  id: "kick",
16
16
  redirectURI,
17
17
  options,
18
18
  authorizationEndpoint: "https://id.kick.com/oauth/authorize",
19
- scopes: _scopes,
19
+ scopes: resolveRequestedScopes(options, KICK_DEFAULT_SCOPES, scopes),
20
20
  codeVerifier,
21
21
  state,
22
22
  additionalParams
@@ -33,6 +33,7 @@ interface LineOptions extends ProviderOptions<LineUserInfo | LineIdTokenPayload>
33
33
  declare const line: (options: LineOptions) => {
34
34
  id: "line";
35
35
  name: string;
36
+ callbackPath: string;
36
37
  createAuthorizationURL({
37
38
  state,
38
39
  scopes,
@@ -48,7 +49,10 @@ declare const line: (options: LineOptions) => {
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,
@@ -60,7 +64,9 @@ declare const line: (options: LineOptions) => {
60
64
  deviceId?: string | undefined;
61
65
  }) => Promise<OAuth2Tokens>;
62
66
  refreshAccessToken: (refreshToken: string) => Promise<OAuth2Tokens>;
63
- verifyIdToken(token: string, nonce: string | undefined): Promise<boolean>;
67
+ idToken: {
68
+ verify: (token: string, nonce: string | undefined) => Promise<boolean>;
69
+ };
64
70
  getUserInfo(token: OAuth2Tokens & {
65
71
  user?: {
66
72
  name?: {
@@ -1,9 +1,15 @@
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 { decodeJwt } from "jose";
5
6
  import { betterFetch } from "@better-fetch/fetch";
6
7
  //#region src/social-providers/line.ts
8
+ const LINE_DEFAULT_SCOPES = [
9
+ "openid",
10
+ "profile",
11
+ "email"
12
+ ];
7
13
  /**
8
14
  * LINE Login v2.1
9
15
  * - Authorization endpoint: https://access.line.me/oauth2/v2.1/authorize
@@ -21,19 +27,13 @@ const line = (options) => {
21
27
  return {
22
28
  id: "line",
23
29
  name: "LINE",
24
- async createAuthorizationURL({ state, scopes, codeVerifier, redirectURI, loginHint, additionalParams }) {
25
- const _scopes = options.disableDefaultScope ? [] : [
26
- "openid",
27
- "profile",
28
- "email"
29
- ];
30
- if (options.scope) _scopes.push(...options.scope);
31
- if (scopes) _scopes.push(...scopes);
32
- return await createAuthorizationURL({
30
+ callbackPath: "/callback/line",
31
+ createAuthorizationURL({ state, scopes, codeVerifier, redirectURI, loginHint, additionalParams }) {
32
+ return createAuthorizationURL({
33
33
  id: "line",
34
34
  options,
35
35
  authorizationEndpoint,
36
- scopes: _scopes,
36
+ scopes: resolveRequestedScopes(options, LINE_DEFAULT_SCOPES, scopes),
37
37
  state,
38
38
  codeVerifier,
39
39
  redirectURI,
@@ -60,9 +60,7 @@ const line = (options) => {
60
60
  tokenEndpoint
61
61
  });
62
62
  },
63
- async verifyIdToken(token, nonce) {
64
- if (options.disableIdTokenSignIn) return false;
65
- if (options.verifyIdToken) return options.verifyIdToken(token, nonce);
63
+ idToken: { verify: async (token, nonce) => {
66
64
  const body = new URLSearchParams();
67
65
  body.set("id_token", token);
68
66
  body.set("client_id", options.clientId);
@@ -76,7 +74,7 @@ const line = (options) => {
76
74
  if (data.aud !== options.clientId) return false;
77
75
  if (data.nonce && data.nonce !== nonce) return false;
78
76
  return true;
79
- },
77
+ } },
80
78
  async getUserInfo(token) {
81
79
  if (options.getUserInfo) return options.getUserInfo(token);
82
80
  let profile = null;
@@ -20,6 +20,7 @@ interface LinearOptions extends ProviderOptions<LinearUser> {
20
20
  declare const linear: (options: LinearOptions) => {
21
21
  id: "linear";
22
22
  name: string;
23
+ callbackPath: string;
23
24
  createAuthorizationURL({
24
25
  state,
25
26
  scopes,
@@ -34,7 +35,10 @@ declare const linear: (options: LinearOptions) => {
34
35
  display?: string | undefined;
35
36
  loginHint?: string | undefined;
36
37
  additionalParams?: Record<string, string> | undefined;
37
- }): Promise<URL>;
38
+ }): Promise<{
39
+ url: URL;
40
+ requestedScopes: string[];
41
+ }>;
38
42
  validateAuthorizationCode: ({
39
43
  code,
40
44
  redirectURI
@@ -1,22 +1,22 @@
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/linear.ts
7
+ const LINEAR_DEFAULT_SCOPES = ["read"];
6
8
  const linear = (options) => {
7
9
  const tokenEndpoint = "https://api.linear.app/oauth/token";
8
10
  return {
9
11
  id: "linear",
10
12
  name: "Linear",
13
+ callbackPath: "/callback/linear",
11
14
  createAuthorizationURL({ state, scopes, loginHint, redirectURI, additionalParams }) {
12
- const _scopes = options.disableDefaultScope ? [] : ["read"];
13
- if (options.scope) _scopes.push(...options.scope);
14
- if (scopes) _scopes.push(...scopes);
15
15
  return createAuthorizationURL({
16
16
  id: "linear",
17
17
  options,
18
18
  authorizationEndpoint: "https://linear.app/oauth/authorize",
19
- scopes: _scopes,
19
+ scopes: resolveRequestedScopes(options, LINEAR_DEFAULT_SCOPES, scopes),
20
20
  state,
21
21
  redirectURI,
22
22
  loginHint,
@@ -19,6 +19,7 @@ interface LinkedInOptions extends ProviderOptions<LinkedInProfile> {
19
19
  declare const linkedin: (options: LinkedInOptions) => {
20
20
  id: "linkedin";
21
21
  name: string;
22
+ callbackPath: string;
22
23
  createAuthorizationURL: ({
23
24
  state,
24
25
  scopes,
@@ -33,7 +34,10 @@ declare const linkedin: (options: LinkedInOptions) => {
33
34
  display?: string | undefined;
34
35
  loginHint?: string | undefined;
35
36
  additionalParams?: Record<string, string> | undefined;
36
- }) => Promise<URL>;
37
+ }) => Promise<{
38
+ url: URL;
39
+ requestedScopes: string[];
40
+ }>;
37
41
  validateAuthorizationCode: ({
38
42
  code,
39
43
  redirectURI
@@ -1,27 +1,27 @@
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/linkedin.ts
7
+ const LINKEDIN_DEFAULT_SCOPES = [
8
+ "profile",
9
+ "email",
10
+ "openid"
11
+ ];
6
12
  const linkedin = (options) => {
7
13
  const authorizationEndpoint = "https://www.linkedin.com/oauth/v2/authorization";
8
14
  const tokenEndpoint = "https://www.linkedin.com/oauth/v2/accessToken";
9
15
  return {
10
16
  id: "linkedin",
11
17
  name: "Linkedin",
12
- createAuthorizationURL: async ({ state, scopes, redirectURI, loginHint, additionalParams }) => {
13
- const _scopes = options.disableDefaultScope ? [] : [
14
- "profile",
15
- "email",
16
- "openid"
17
- ];
18
- if (options.scope) _scopes.push(...options.scope);
19
- if (scopes) _scopes.push(...scopes);
20
- return await createAuthorizationURL({
18
+ callbackPath: "/callback/linkedin",
19
+ createAuthorizationURL: ({ state, scopes, redirectURI, loginHint, additionalParams }) => {
20
+ return createAuthorizationURL({
21
21
  id: "linkedin",
22
22
  options,
23
23
  authorizationEndpoint,
24
- scopes: _scopes,
24
+ scopes: resolveRequestedScopes(options, LINKEDIN_DEFAULT_SCOPES, scopes),
25
25
  state,
26
26
  loginHint,
27
27
  redirectURI,
@@ -1,4 +1,7 @@
1
+ import { ClientAssertionGetter } from "../oauth2/client-assertion.mjs";
1
2
  import { OAuth2Tokens, ProviderOptions } from "../oauth2/oauth-provider.mjs";
3
+ import * as jose from "jose";
4
+
2
5
  //#region src/social-providers/microsoft-entra-id.d.ts
3
6
  /**
4
7
  * @see [Microsoft Identity Platform - Optional claims reference](https://learn.microsoft.com/en-us/entra/identity-platform/optional-claims-reference)
@@ -109,25 +112,34 @@ interface MicrosoftOptions extends ProviderOptions<MicrosoftEntraIDProfile> {
109
112
  * The tenant ID of the Microsoft account
110
113
  * @default "common"
111
114
  */
112
- tenantId?: string | undefined;
115
+ tenantId?: string;
113
116
  /**
114
117
  * The authentication authority URL. Use the default "https://login.microsoftonline.com" for standard Entra ID or "https://<tenant-id>.ciamlogin.com" for CIAM scenarios.
115
118
  * @default "https://login.microsoftonline.com"
116
119
  */
117
- authority?: string | undefined;
120
+ authority?: string;
121
+ /**
122
+ * Function that returns a JWT client assertion for token endpoint authentication.
123
+ *
124
+ * Use this instead of `clientSecret` when your Microsoft Entra ID app is
125
+ * configured for client authentication with assertions (private_key_jwt or
126
+ * workload identity federation).
127
+ */
128
+ clientAssertion?: ClientAssertionGetter;
118
129
  /**
119
130
  * The size of the profile photo
120
131
  * @default 48
121
132
  */
122
- profilePhotoSize?: (48 | 64 | 96 | 120 | 240 | 360 | 432 | 504 | 648) | undefined;
133
+ profilePhotoSize?: 48 | 64 | 96 | 120 | 240 | 360 | 432 | 504 | 648;
123
134
  /**
124
135
  * Disable profile photo
125
136
  */
126
- disableProfilePhoto?: boolean | undefined;
137
+ disableProfilePhoto?: boolean;
127
138
  }
128
139
  declare const microsoft: (options: MicrosoftOptions) => {
129
140
  id: "microsoft";
130
141
  name: string;
142
+ callbackPath: string;
131
143
  createAuthorizationURL(data: {
132
144
  state: string;
133
145
  codeVerifier: string;
@@ -136,7 +148,10 @@ declare const microsoft: (options: MicrosoftOptions) => {
136
148
  display?: string | undefined;
137
149
  loginHint?: string | undefined;
138
150
  additionalParams?: Record<string, string> | undefined;
139
- }): Promise<URL>;
151
+ }): Promise<{
152
+ url: URL;
153
+ requestedScopes: string[];
154
+ }>;
140
155
  validateAuthorizationCode({
141
156
  code,
142
157
  codeVerifier,
@@ -147,7 +162,17 @@ declare const microsoft: (options: MicrosoftOptions) => {
147
162
  codeVerifier?: string | undefined;
148
163
  deviceId?: string | undefined;
149
164
  }): Promise<OAuth2Tokens>;
150
- verifyIdToken(token: string, nonce: string | undefined): Promise<boolean>;
165
+ idToken: {
166
+ jwks: (header: jose.JWTHeaderParameters) => Promise<Uint8Array<ArrayBufferLike> | CryptoKey>;
167
+ audience: string | string[];
168
+ maxTokenAge: string;
169
+ /**
170
+ * Issuer varies per tenant for multi-tenant endpoints, so only validate it for
171
+ * specific tenants.
172
+ * @see https://learn.microsoft.com/en-us/entra/identity-platform/v2-protocols#endpoints
173
+ */
174
+ issuer: string | undefined;
175
+ };
151
176
  getUserInfo(token: OAuth2Tokens & {
152
177
  user?: {
153
178
  name?: {
@@ -1,42 +1,48 @@
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
8
  import { base64 } from "@better-auth/utils/base64";
8
- import { decodeJwt, decodeProtectedHeader, importJWK, jwtVerify } from "jose";
9
+ import { decodeJwt, importJWK } from "jose";
9
10
  import { betterFetch } from "@better-fetch/fetch";
10
11
  //#region src/social-providers/microsoft-entra-id.ts
12
+ const MICROSOFT_ENTRA_ID_DEFAULT_SCOPES = [
13
+ "openid",
14
+ "profile",
15
+ "email",
16
+ "User.Read",
17
+ "offline_access"
18
+ ];
11
19
  const microsoft = (options) => {
12
20
  const tenant = options.tenantId || "common";
13
21
  const authority = options.authority || "https://login.microsoftonline.com";
14
22
  const authorizationEndpoint = `${authority}/${tenant}/oauth2/v2.0/authorize`;
15
23
  const tokenEndpoint = `${authority}/${tenant}/oauth2/v2.0/token`;
24
+ if (options.clientSecret && options.clientAssertion) throw new BetterAuthError("Microsoft Entra ID clientAssertion cannot be combined with clientSecret");
25
+ const tokenEndpointAuth = options.clientAssertion ? {
26
+ method: "private_key_jwt",
27
+ getClientAssertion: options.clientAssertion
28
+ } : void 0;
16
29
  return {
17
30
  id: "microsoft",
18
31
  name: "Microsoft EntraID",
32
+ callbackPath: "/callback/microsoft",
19
33
  createAuthorizationURL(data) {
20
34
  if (!getPrimaryClientId(options.clientId)) {
21
35
  logger.error("Client Id is required for Microsoft Entra ID. Make sure to provide it in the options.");
22
36
  throw new BetterAuthError("CLIENT_ID_AND_SECRET_REQUIRED");
23
37
  }
24
- const scopes = options.disableDefaultScope ? [] : [
25
- "openid",
26
- "profile",
27
- "email",
28
- "User.Read",
29
- "offline_access"
30
- ];
31
- if (options.scope) scopes.push(...options.scope);
32
- if (data.scopes) scopes.push(...data.scopes);
38
+ const requestedScopes = resolveRequestedScopes(options, MICROSOFT_ENTRA_ID_DEFAULT_SCOPES, data.scopes);
33
39
  return createAuthorizationURL({
34
40
  id: "microsoft",
35
41
  options,
36
42
  authorizationEndpoint,
37
43
  state: data.state,
38
44
  codeVerifier: data.codeVerifier,
39
- scopes,
45
+ scopes: requestedScopes,
40
46
  redirectURI: data.redirectURI,
41
47
  prompt: options.prompt,
42
48
  loginHint: data.loginHint,
@@ -49,33 +55,15 @@ const microsoft = (options) => {
49
55
  codeVerifier,
50
56
  redirectURI,
51
57
  options,
52
- tokenEndpoint
58
+ tokenEndpoint,
59
+ tokenEndpointAuth
53
60
  });
54
61
  },
55
- async verifyIdToken(token, nonce) {
56
- if (options.disableIdTokenSignIn) return false;
57
- if (options.verifyIdToken) return options.verifyIdToken(token, nonce);
58
- try {
59
- const { kid, alg: jwtAlg } = decodeProtectedHeader(token);
60
- if (!kid || !jwtAlg) return false;
61
- const publicKey = await getMicrosoftPublicKey(kid, tenant, authority);
62
- const verifyOptions = {
63
- algorithms: [jwtAlg],
64
- audience: options.clientId,
65
- maxTokenAge: "1h"
66
- };
67
- /**
68
- * Issuer varies per user's tenant for multi-tenant endpoints, so only validate for specific tenants.
69
- * @see https://learn.microsoft.com/en-us/entra/identity-platform/v2-protocols#endpoints
70
- */
71
- if (tenant !== "common" && tenant !== "organizations" && tenant !== "consumers") verifyOptions.issuer = `${authority}/${tenant}/v2.0`;
72
- const { payload: jwtClaims } = await jwtVerify(token, publicKey, verifyOptions);
73
- if (nonce && jwtClaims.nonce !== nonce) return false;
74
- return true;
75
- } catch (error) {
76
- logger.error("Failed to verify ID token:", error);
77
- return false;
78
- }
62
+ idToken: {
63
+ jwks: (header) => getMicrosoftPublicKey(header.kid, tenant, authority),
64
+ audience: options.clientId,
65
+ maxTokenAge: "1h",
66
+ issuer: tenant !== "common" && tenant !== "organizations" && tenant !== "consumers" ? `${authority}/${tenant}/v2.0` : void 0
79
67
  },
80
68
  async getUserInfo(token) {
81
69
  if (options.getUserInfo) return options.getUserInfo(token);
@@ -124,7 +112,8 @@ const microsoft = (options) => {
124
112
  clientSecret: options.clientSecret
125
113
  },
126
114
  extraParams: { scope: scopes.join(" ") },
127
- tokenEndpoint
115
+ tokenEndpoint,
116
+ tokenEndpointAuth
128
117
  });
129
118
  },
130
119
  options
@@ -24,6 +24,7 @@ interface NaverOptions extends ProviderOptions<NaverProfile> {
24
24
  declare const naver: (options: NaverOptions) => {
25
25
  id: "naver";
26
26
  name: string;
27
+ callbackPath: string;
27
28
  createAuthorizationURL({
28
29
  state,
29
30
  scopes,
@@ -37,7 +38,10 @@ declare const naver: (options: NaverOptions) => {
37
38
  display?: string | undefined;
38
39
  loginHint?: string | undefined;
39
40
  additionalParams?: Record<string, string> | undefined;
40
- }): Promise<URL>;
41
+ }): Promise<{
42
+ url: URL;
43
+ requestedScopes: string[];
44
+ }>;
41
45
  validateAuthorizationCode: ({
42
46
  code,
43
47
  redirectURI
@@ -1,22 +1,22 @@
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/naver.ts
7
+ const NAVER_DEFAULT_SCOPES = ["profile", "email"];
6
8
  const naver = (options) => {
7
9
  const tokenEndpoint = "https://nid.naver.com/oauth2.0/token";
8
10
  return {
9
11
  id: "naver",
10
12
  name: "Naver",
13
+ callbackPath: "/callback/naver",
11
14
  createAuthorizationURL({ state, scopes, redirectURI, additionalParams }) {
12
- const _scopes = options.disableDefaultScope ? [] : ["profile", "email"];
13
- if (options.scope) _scopes.push(...options.scope);
14
- if (scopes) _scopes.push(...scopes);
15
15
  return createAuthorizationURL({
16
16
  id: "naver",
17
17
  options,
18
18
  authorizationEndpoint: "https://nid.naver.com/oauth2.0/authorize",
19
- scopes: _scopes,
19
+ scopes: resolveRequestedScopes(options, NAVER_DEFAULT_SCOPES, scopes),
20
20
  state,
21
21
  redirectURI,
22
22
  additionalParams
@@ -16,6 +16,7 @@ interface NotionOptions extends ProviderOptions<NotionProfile> {
16
16
  declare const notion: (options: NotionOptions) => {
17
17
  id: "notion";
18
18
  name: string;
19
+ callbackPath: string;
19
20
  createAuthorizationURL({
20
21
  state,
21
22
  scopes,
@@ -30,7 +31,10 @@ declare const notion: (options: NotionOptions) => {
30
31
  display?: string | undefined;
31
32
  loginHint?: string | undefined;
32
33
  additionalParams?: Record<string, string> | undefined;
33
- }): Promise<URL>;
34
+ }): Promise<{
35
+ url: URL;
36
+ requestedScopes: string[];
37
+ }>;
34
38
  validateAuthorizationCode: ({
35
39
  code,
36
40
  redirectURI
@@ -1,22 +1,22 @@
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/notion.ts
7
+ const NOTION_DEFAULT_SCOPES = [];
6
8
  const notion = (options) => {
7
9
  const tokenEndpoint = "https://api.notion.com/v1/oauth/token";
8
10
  return {
9
11
  id: "notion",
10
12
  name: "Notion",
13
+ callbackPath: "/callback/notion",
11
14
  createAuthorizationURL({ state, scopes, loginHint, redirectURI, additionalParams }) {
12
- const _scopes = options.disableDefaultScope ? [] : [];
13
- if (options.scope) _scopes.push(...options.scope);
14
- if (scopes) _scopes.push(...scopes);
15
15
  return createAuthorizationURL({
16
16
  id: "notion",
17
17
  options,
18
18
  authorizationEndpoint: "https://api.notion.com/v1/oauth/authorize",
19
- scopes: _scopes,
19
+ scopes: resolveRequestedScopes(options, NOTION_DEFAULT_SCOPES, scopes),
20
20
  state,
21
21
  redirectURI,
22
22
  loginHint,
@@ -21,6 +21,7 @@ interface PaybinOptions extends ProviderOptions<PaybinProfile> {
21
21
  declare const paybin: (options: PaybinOptions) => {
22
22
  id: "paybin";
23
23
  name: string;
24
+ callbackPath: string;
24
25
  createAuthorizationURL({
25
26
  state,
26
27
  scopes,
@@ -36,7 +37,10 @@ declare const paybin: (options: PaybinOptions) => {
36
37
  display?: string | undefined;
37
38
  loginHint?: string | undefined;
38
39
  additionalParams?: Record<string, string> | undefined;
39
- }): Promise<URL>;
40
+ }): Promise<{
41
+ url: URL;
42
+ requestedScopes: string[];
43
+ }>;
40
44
  validateAuthorizationCode: ({
41
45
  code,
42
46
  codeVerifier,
@@ -1,10 +1,16 @@
1
1
  import { BetterAuthError } from "../error/index.mjs";
2
2
  import { logger } from "../env/logger.mjs";
3
+ import { resolveRequestedScopes } from "../oauth2/scopes.mjs";
3
4
  import { createAuthorizationURL } from "../oauth2/create-authorization-url.mjs";
4
5
  import { refreshAccessToken } from "../oauth2/refresh-access-token.mjs";
5
6
  import { validateAuthorizationCode } from "../oauth2/validate-authorization-code.mjs";
6
7
  import { decodeJwt } from "jose";
7
8
  //#region src/social-providers/paybin.ts
9
+ const PAYBIN_DEFAULT_SCOPES = [
10
+ "openid",
11
+ "email",
12
+ "profile"
13
+ ];
8
14
  const paybin = (options) => {
9
15
  const issuer = options.issuer || "https://idp.paybin.io";
10
16
  const authorizationEndpoint = `${issuer}/oauth2/authorize`;
@@ -12,24 +18,18 @@ const paybin = (options) => {
12
18
  return {
13
19
  id: "paybin",
14
20
  name: "Paybin",
15
- async createAuthorizationURL({ state, scopes, codeVerifier, redirectURI, loginHint, additionalParams }) {
21
+ callbackPath: "/callback/paybin",
22
+ createAuthorizationURL({ state, scopes, codeVerifier, redirectURI, loginHint, additionalParams }) {
16
23
  if (!options.clientId || !options.clientSecret) {
17
24
  logger.error("Client Id and Client Secret is required for Paybin. Make sure to provide them in the options.");
18
25
  throw new BetterAuthError("CLIENT_ID_AND_SECRET_REQUIRED");
19
26
  }
20
27
  if (!codeVerifier) throw new BetterAuthError("codeVerifier is required for Paybin");
21
- const _scopes = options.disableDefaultScope ? [] : [
22
- "openid",
23
- "email",
24
- "profile"
25
- ];
26
- if (options.scope) _scopes.push(...options.scope);
27
- if (scopes) _scopes.push(...scopes);
28
- return await createAuthorizationURL({
28
+ return createAuthorizationURL({
29
29
  id: "paybin",
30
30
  options,
31
31
  authorizationEndpoint,
32
- scopes: _scopes,
32
+ scopes: resolveRequestedScopes(options, PAYBIN_DEFAULT_SCOPES, scopes),
33
33
  state,
34
34
  codeVerifier,
35
35
  redirectURI,