@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
@@ -1,7 +1,7 @@
1
1
  import { SignJWT, importJWK, importPKCS8 } from "jose";
2
2
  //#region src/oauth2/client-assertion.ts
3
3
  /** Asymmetric signing algorithms compatible with private_key_jwt (RFC 7523). */
4
- const ASSERTION_SIGNING_ALGORITHMS = [
4
+ const PRIVATE_KEY_JWT_SIGNING_ALGORITHMS = [
5
5
  "RS256",
6
6
  "RS384",
7
7
  "RS512",
@@ -13,20 +13,46 @@ const ASSERTION_SIGNING_ALGORITHMS = [
13
13
  "ES512",
14
14
  "EdDSA"
15
15
  ];
16
+ function assertSupportedPrivateKeyJwtAlgorithm(candidate) {
17
+ if (!PRIVATE_KEY_JWT_SIGNING_ALGORITHMS.includes(candidate)) throw new Error(`Unsupported private_key_jwt signing algorithm: ${candidate}. Use one of ${PRIVATE_KEY_JWT_SIGNING_ALGORITHMS.join(", ")}.`);
18
+ }
19
+ /**
20
+ * Validates `private_key_jwt` options eagerly and returns the algorithm to
21
+ * use for signing.
22
+ *
23
+ * Asserts that key material is configured, that any explicit `algorithm` is
24
+ * supported, that any JWK-embedded `alg` is supported, and that the two
25
+ * agree when both are set.
26
+ */
27
+ function resolveValidPrivateKeyJwtOptions(options) {
28
+ if (!options.privateKeyJwk && !options.privateKeyPem) throw new Error("private_key_jwt requires either privateKeyJwk or privateKeyPem");
29
+ if (options.algorithm) assertSupportedPrivateKeyJwtAlgorithm(options.algorithm);
30
+ const jwkAlg = options.privateKeyJwk?.alg;
31
+ if (typeof jwkAlg === "string") assertSupportedPrivateKeyJwtAlgorithm(jwkAlg);
32
+ if (options.algorithm && typeof jwkAlg === "string" && options.algorithm !== jwkAlg) throw new Error(`JWK alg "${jwkAlg}" does not match configured algorithm "${options.algorithm}". Remove the JWK alg field, or pass an algorithm that matches the JWK.`);
33
+ return options.algorithm ?? (typeof jwkAlg === "string" ? jwkAlg : "RS256");
34
+ }
16
35
  const CLIENT_ASSERTION_TYPE = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer";
17
36
  /**
18
37
  * Signs an RFC 7523 client assertion JWT for `private_key_jwt` authentication.
19
38
  *
20
- * The JWT contains: iss=clientId, sub=clientId, aud=tokenEndpoint,
21
- * exp=now+120s, jti=unique, iat=now.
39
+ * The JWT contains these claims:
40
+ *
41
+ * - iss=clientId
42
+ * - sub=clientId
43
+ * - aud=tokenEndpoint
44
+ * - exp=now + 120s
45
+ * - jti=unique
46
+ * - iat=now
22
47
  */
23
- async function signClientAssertion({ clientId, tokenEndpoint, privateKeyJwk, privateKeyPem, kid, algorithm, expiresIn = 120 }) {
48
+ async function signPrivateKeyJwtClientAssertion({ clientId, tokenEndpoint, privateKeyJwk, privateKeyPem, kid, algorithm, expiresIn = 120 }) {
49
+ const resolvedAlg = resolveValidPrivateKeyJwtOptions({
50
+ privateKeyJwk,
51
+ privateKeyPem,
52
+ algorithm
53
+ });
24
54
  const resolvedKid = kid ?? privateKeyJwk?.kid;
25
- const resolvedAlg = algorithm ?? privateKeyJwk?.alg ?? "RS256";
26
- let key;
27
- if (privateKeyJwk) key = await importJWK(privateKeyJwk, resolvedAlg);
28
- else if (privateKeyPem) key = await importPKCS8(privateKeyPem, resolvedAlg);
29
- else throw new Error("private_key_jwt requires either privateKeyJwk or privateKeyPem");
55
+ const key = privateKeyJwk ? await importJWK(privateKeyJwk, resolvedAlg) : await importPKCS8(privateKeyPem, resolvedAlg);
30
56
  const now = Math.floor(Date.now() / 1e3);
31
57
  const jti = crypto.randomUUID();
32
58
  const header = {
@@ -37,28 +63,37 @@ async function signClientAssertion({ clientId, tokenEndpoint, privateKeyJwk, pri
37
63
  return new SignJWT({}).setProtectedHeader(header).setIssuer(clientId).setSubject(clientId).setAudience(tokenEndpoint).setIssuedAt(now).setExpirationTime(now + expiresIn).setJti(jti).sign(key);
38
64
  }
39
65
  /**
40
- * Resolves a ClientAssertionConfig into `client_assertion` + `client_assertion_type`
41
- * params for injection into a token request body.
66
+ * Creates a client assertion getter for `private_key_jwt` authentication.
67
+ *
68
+ * Validates options eagerly (key material, supported algorithm, JWK alg
69
+ * agreement) so misconfiguration surfaces at construction rather than on the
70
+ * first token request. The returned function signs a fresh RFC 7523 JWT
71
+ * assertion for every token endpoint request.
72
+ */
73
+ function createPrivateKeyJwtClientAssertionGetter(options) {
74
+ resolveValidPrivateKeyJwtOptions({
75
+ privateKeyJwk: options.privateKeyJwk,
76
+ privateKeyPem: options.privateKeyPem,
77
+ algorithm: options.algorithm
78
+ });
79
+ return ({ clientId, tokenEndpoint }) => signPrivateKeyJwtClientAssertion({
80
+ clientId,
81
+ tokenEndpoint,
82
+ privateKeyJwk: options.privateKeyJwk,
83
+ privateKeyPem: options.privateKeyPem,
84
+ kid: options.kid,
85
+ algorithm: options.algorithm,
86
+ expiresIn: options.expiresIn
87
+ });
88
+ }
89
+ /**
90
+ * Resolves a client assertion getter into `client_assertion` + `client_assertion_type` params for injection into a token request body.
42
91
  */
43
- async function resolveAssertionParams({ clientAssertion, clientId, tokenEndpoint }) {
44
- let assertion = clientAssertion.assertion;
45
- if (!assertion) {
46
- const audEndpoint = tokenEndpoint ?? clientAssertion.tokenEndpoint;
47
- if (!audEndpoint) throw new Error("private_key_jwt requires a tokenEndpoint for the JWT audience claim");
48
- assertion = await signClientAssertion({
49
- clientId,
50
- tokenEndpoint: audEndpoint,
51
- privateKeyJwk: clientAssertion.privateKeyJwk,
52
- privateKeyPem: clientAssertion.privateKeyPem,
53
- kid: clientAssertion.kid,
54
- algorithm: clientAssertion.algorithm,
55
- expiresIn: clientAssertion.expiresIn
56
- });
57
- }
92
+ async function resolveClientAssertionParams({ getClientAssertion, context }) {
58
93
  return {
59
- client_assertion: assertion,
94
+ client_assertion: await getClientAssertion(context),
60
95
  client_assertion_type: CLIENT_ASSERTION_TYPE
61
96
  };
62
97
  }
63
98
  //#endregion
64
- export { ASSERTION_SIGNING_ALGORITHMS, CLIENT_ASSERTION_TYPE, resolveAssertionParams, signClientAssertion };
99
+ export { CLIENT_ASSERTION_TYPE, PRIVATE_KEY_JWT_SIGNING_ALGORITHMS, createPrivateKeyJwtClientAssertionGetter, resolveClientAssertionParams, signPrivateKeyJwtClientAssertion };
@@ -1,59 +1,38 @@
1
- import { ClientAssertionConfig } from "./client-assertion.mjs";
2
1
  import { AwaitableFunction } from "../types/helper.mjs";
3
2
  import { OAuth2Tokens, ProviderOptions } from "./oauth-provider.mjs";
3
+ import { TokenEndpointAuth, TokenEndpointSecretAuthentication } from "./token-endpoint-auth.mjs";
4
4
 
5
5
  //#region src/oauth2/client-credentials-token.d.ts
6
- declare function clientCredentialsTokenRequest({
7
- options,
8
- scope,
9
- authentication,
10
- clientAssertion,
11
- tokenEndpoint,
12
- resource
13
- }: {
6
+ interface ClientCredentialsTokenRequestInput {
14
7
  options: AwaitableFunction<ProviderOptions>;
15
8
  scope?: string | undefined;
16
- authentication?: ("basic" | "post" | "private_key_jwt") | undefined;
17
- clientAssertion?: ClientAssertionConfig | undefined; /** Token endpoint URL. Used as the JWT `aud` claim when signing assertions. */
9
+ authentication?: TokenEndpointSecretAuthentication | undefined;
10
+ tokenEndpointAuth?: TokenEndpointAuth | undefined;
18
11
  tokenEndpoint?: string | undefined;
19
12
  resource?: (string | string[]) | undefined;
20
- }): Promise<{
21
- body: URLSearchParams;
22
- headers: Record<string, any>;
23
- }>;
24
- /**
25
- * @deprecated use async'd clientCredentialsTokenRequest instead
26
- */
27
- declare function createClientCredentialsTokenRequest({
13
+ }
14
+ interface ClientCredentialsTokenInput extends ClientCredentialsTokenRequestInput {
15
+ tokenEndpoint: string;
16
+ scope: string;
17
+ }
18
+ declare function clientCredentialsTokenRequest({
28
19
  options,
29
20
  scope,
30
21
  authentication,
31
- resource,
32
- extraParams
33
- }: {
34
- options: ProviderOptions;
35
- scope?: string | undefined;
36
- authentication?: ("basic" | "post" | "private_key_jwt") | undefined;
37
- resource?: (string | string[]) | undefined;
38
- extraParams?: Record<string, string> | undefined;
39
- }): {
22
+ tokenEndpointAuth,
23
+ tokenEndpoint,
24
+ resource
25
+ }: ClientCredentialsTokenRequestInput): Promise<{
40
26
  body: URLSearchParams;
41
- headers: Record<string, any>;
42
- };
27
+ headers: Record<string, string>;
28
+ }>;
43
29
  declare function clientCredentialsToken({
44
30
  options,
45
31
  tokenEndpoint,
46
32
  scope,
47
33
  authentication,
48
- clientAssertion,
34
+ tokenEndpointAuth,
49
35
  resource
50
- }: {
51
- options: AwaitableFunction<ProviderOptions>;
52
- tokenEndpoint: string;
53
- scope: string;
54
- authentication?: ("basic" | "post" | "private_key_jwt") | undefined;
55
- clientAssertion?: ClientAssertionConfig | undefined;
56
- resource?: (string | string[]) | undefined;
57
- }): Promise<OAuth2Tokens>;
36
+ }: ClientCredentialsTokenInput): Promise<OAuth2Tokens>;
58
37
  //#endregion
59
- export { clientCredentialsToken, clientCredentialsTokenRequest, createClientCredentialsTokenRequest };
38
+ export { clientCredentialsToken, clientCredentialsTokenRequest };
@@ -1,30 +1,25 @@
1
- import { resolveAssertionParams } from "./client-assertion.mjs";
2
- import { base64 } from "@better-auth/utils/base64";
1
+ import { applyTokenEndpointAuth } from "./token-endpoint-auth.mjs";
3
2
  import { betterFetch } from "@better-fetch/fetch";
4
3
  //#region src/oauth2/client-credentials-token.ts
5
- async function clientCredentialsTokenRequest({ options, scope, authentication, clientAssertion, tokenEndpoint, resource }) {
4
+ async function clientCredentialsTokenRequest({ options, scope, authentication, tokenEndpointAuth, tokenEndpoint, resource }) {
6
5
  options = typeof options === "function" ? await options() : options;
7
- let extraParams;
8
- if (authentication === "private_key_jwt") {
9
- if (!clientAssertion) throw new Error("private_key_jwt authentication requires a clientAssertion configuration");
10
- extraParams = await resolveAssertionParams({
11
- clientAssertion,
12
- clientId: Array.isArray(options.clientId) ? options.clientId[0] : options.clientId,
13
- tokenEndpoint
14
- });
15
- }
16
- return createClientCredentialsTokenRequest({
6
+ const request = buildClientCredentialsTokenRequest({
17
7
  options,
18
8
  scope,
19
- authentication,
20
- resource,
21
- extraParams
9
+ resource
22
10
  });
11
+ await applyTokenEndpointAuth({
12
+ body: request.body,
13
+ headers: request.headers,
14
+ options,
15
+ tokenEndpoint: tokenEndpoint ?? "",
16
+ grantType: "client_credentials",
17
+ tokenEndpointAuth,
18
+ authentication
19
+ });
20
+ return request;
23
21
  }
24
- /**
25
- * @deprecated use async'd clientCredentialsTokenRequest instead
26
- */
27
- function createClientCredentialsTokenRequest({ options, scope, authentication, resource, extraParams }) {
22
+ function buildClientCredentialsTokenRequest({ options, scope, resource, extraParams }) {
28
23
  const body = new URLSearchParams();
29
24
  const headers = {
30
25
  "content-type": "application/x-www-form-urlencoded",
@@ -34,12 +29,6 @@ function createClientCredentialsTokenRequest({ options, scope, authentication, r
34
29
  scope && body.set("scope", scope);
35
30
  if (resource) if (typeof resource === "string") body.append("resource", resource);
36
31
  else for (const _resource of resource) body.append("resource", _resource);
37
- const primaryClientId = Array.isArray(options.clientId) ? options.clientId[0] : options.clientId;
38
- if (authentication === "basic") headers["authorization"] = `Basic ${base64.encode(`${primaryClientId}:${options.clientSecret ?? ""}`)}`;
39
- else {
40
- body.set("client_id", primaryClientId);
41
- if (authentication !== "private_key_jwt" && options.clientSecret) body.set("client_secret", options.clientSecret);
42
- }
43
32
  if (extraParams) {
44
33
  for (const [key, value] of Object.entries(extraParams)) if (!body.has(key)) body.append(key, value);
45
34
  }
@@ -48,12 +37,12 @@ function createClientCredentialsTokenRequest({ options, scope, authentication, r
48
37
  headers
49
38
  };
50
39
  }
51
- async function clientCredentialsToken({ options, tokenEndpoint, scope, authentication, clientAssertion, resource }) {
40
+ async function clientCredentialsToken({ options, tokenEndpoint, scope, authentication, tokenEndpointAuth, resource }) {
52
41
  const { body, headers } = await clientCredentialsTokenRequest({
53
42
  options,
54
43
  scope,
55
44
  authentication,
56
- clientAssertion,
45
+ tokenEndpointAuth,
57
46
  tokenEndpoint,
58
47
  resource
59
48
  });
@@ -75,4 +64,4 @@ async function clientCredentialsToken({ options, tokenEndpoint, scope, authentic
75
64
  return tokens;
76
65
  }
77
66
  //#endregion
78
- export { clientCredentialsToken, clientCredentialsTokenRequest, createClientCredentialsTokenRequest };
67
+ export { clientCredentialsToken, clientCredentialsTokenRequest };
@@ -1,6 +1,14 @@
1
1
  import { AwaitableFunction } from "../types/helper.mjs";
2
2
  import { ProviderOptions } from "./oauth-provider.mjs";
3
3
  //#region src/oauth2/create-authorization-url.d.ts
4
+ /**
5
+ * Query-parameter names that are populated by the framework as part of the
6
+ * authorization request and must not be overridden by caller-supplied
7
+ * `additionalParams`. Overriding `state`, PKCE, or `redirect_uri` would
8
+ * break the callback correlation and session pinning guarantees.
9
+ */
10
+ declare const RESERVED_AUTHORIZATION_PARAMS: readonly ["state", "client_id", "redirect_uri", "response_type", "code_challenge", "code_challenge_method", "scope"];
11
+ declare const RESERVED_AUTHORIZATION_PARAMS_SET: ReadonlySet<string>;
4
12
  declare function createAuthorizationURL({
5
13
  id,
6
14
  options,
@@ -39,6 +47,9 @@ declare function createAuthorizationURL({
39
47
  responseMode?: string | undefined;
40
48
  additionalParams?: Record<string, string> | undefined;
41
49
  scopeJoiner?: string | undefined;
42
- }): Promise<URL>;
50
+ }): Promise<{
51
+ url: URL;
52
+ requestedScopes: string[];
53
+ }>;
43
54
  //#endregion
44
- export { createAuthorizationURL };
55
+ export { RESERVED_AUTHORIZATION_PARAMS, RESERVED_AUTHORIZATION_PARAMS_SET, createAuthorizationURL };
@@ -1,13 +1,30 @@
1
- import { generateCodeChallenge } from "./utils.mjs";
1
+ import { generateCodeChallenge, getPrimaryClientId } from "./utils.mjs";
2
2
  //#region src/oauth2/create-authorization-url.ts
3
+ /**
4
+ * Query-parameter names that are populated by the framework as part of the
5
+ * authorization request and must not be overridden by caller-supplied
6
+ * `additionalParams`. Overriding `state`, PKCE, or `redirect_uri` would
7
+ * break the callback correlation and session pinning guarantees.
8
+ */
9
+ const RESERVED_AUTHORIZATION_PARAMS = [
10
+ "state",
11
+ "client_id",
12
+ "redirect_uri",
13
+ "response_type",
14
+ "code_challenge",
15
+ "code_challenge_method",
16
+ "scope"
17
+ ];
18
+ const RESERVED_AUTHORIZATION_PARAMS_SET = new Set(RESERVED_AUTHORIZATION_PARAMS);
3
19
  async function createAuthorizationURL({ id, options, authorizationEndpoint, state, codeVerifier, scopes, claims, redirectURI, duration, prompt, accessType, responseType, display, loginHint, hd, responseMode, additionalParams, scopeJoiner }) {
4
20
  options = typeof options === "function" ? await options() : options;
5
21
  const url = new URL(options.authorizationEndpoint || authorizationEndpoint);
6
22
  url.searchParams.set("response_type", responseType || "code");
7
- const primaryClientId = Array.isArray(options.clientId) ? options.clientId[0] : options.clientId;
23
+ const primaryClientId = getPrimaryClientId(options.clientId);
24
+ if (!primaryClientId) throw new Error("OAuth provider requires clientId");
8
25
  url.searchParams.set("client_id", primaryClientId);
9
26
  url.searchParams.set("state", state);
10
- if (scopes) url.searchParams.set("scope", scopes.join(scopeJoiner || " "));
27
+ if (scopes?.length) url.searchParams.set("scope", scopes.join(scopeJoiner || " "));
11
28
  url.searchParams.set("redirect_uri", options.redirectURI || redirectURI);
12
29
  duration && url.searchParams.set("duration", duration);
13
30
  display && url.searchParams.set("display", display);
@@ -32,10 +49,14 @@ async function createAuthorizationURL({ id, options, authorizationEndpoint, stat
32
49
  ...claimsObj
33
50
  } }));
34
51
  }
35
- if (additionalParams) Object.entries(additionalParams).forEach(([key, value]) => {
52
+ if (additionalParams) for (const [key, value] of Object.entries(additionalParams)) {
53
+ if (RESERVED_AUTHORIZATION_PARAMS_SET.has(key)) continue;
36
54
  url.searchParams.set(key, value);
37
- });
38
- return url;
55
+ }
56
+ return {
57
+ url,
58
+ requestedScopes: scopes ?? []
59
+ };
39
60
  }
40
61
  //#endregion
41
- export { createAuthorizationURL };
62
+ export { RESERVED_AUTHORIZATION_PARAMS, RESERVED_AUTHORIZATION_PARAMS_SET, createAuthorizationURL };
@@ -1,9 +1,14 @@
1
- import { ASSERTION_SIGNING_ALGORITHMS, AssertionSigningAlgorithm, CLIENT_ASSERTION_TYPE, ClientAssertionConfig, resolveAssertionParams, signClientAssertion } from "./client-assertion.mjs";
2
- import { OAuth2Tokens, OAuth2UserInfo, OAuthProvider, ProviderOptions } from "./oauth-provider.mjs";
3
- import { clientCredentialsToken, clientCredentialsTokenRequest, createClientCredentialsTokenRequest } from "./client-credentials-token.mjs";
4
- import { createAuthorizationURL } from "./create-authorization-url.mjs";
5
- import { createRefreshAccessTokenRequest, refreshAccessToken, refreshAccessTokenRequest } from "./refresh-access-token.mjs";
6
- import { generateCodeChallenge, getOAuth2Tokens, getPrimaryClientId } from "./utils.mjs";
7
- import { authorizationCodeRequest, createAuthorizationCodeRequest, validateAuthorizationCode, validateToken } from "./validate-authorization-code.mjs";
1
+ import { additionalAuthorizationParamsSchema } from "./authorization-params.mjs";
2
+ import { decodeBasicCredentials, encodeBasicCredentials } from "./basic-credentials.mjs";
3
+ import { CLIENT_ASSERTION_TYPE, ClientAssertionContext, ClientAssertionGetter, ClientAssertionGrantType, PRIVATE_KEY_JWT_SIGNING_ALGORITHMS, PrivateKeyJwtClientAssertionGetterOptions, PrivateKeyJwtSigningAlgorithm, createPrivateKeyJwtClientAssertionGetter, resolveClientAssertionParams, signPrivateKeyJwtClientAssertion } from "./client-assertion.mjs";
4
+ import { AuthorizationURLResult, GrantAuthority, OAuth2Tokens, OAuth2UserInfo, OAuthIdTokenConfig, ProviderGrantAuthority, ProviderOptions, UpstreamProvider } from "./oauth-provider.mjs";
5
+ import { TokenEndpointAuth, TokenEndpointAuthMethod, TokenEndpointSecretAuthentication } from "./token-endpoint-auth.mjs";
6
+ import { clientCredentialsToken, clientCredentialsTokenRequest } from "./client-credentials-token.mjs";
7
+ import { RESERVED_AUTHORIZATION_PARAMS, RESERVED_AUTHORIZATION_PARAMS_SET, createAuthorizationURL } from "./create-authorization-url.mjs";
8
+ import { refreshAccessToken, refreshAccessTokenRequest } from "./refresh-access-token.mjs";
9
+ import { includesGrantedScope, normalizeScopes, parseScopeField, readGrantedScopes, resolveRequestedScopes, unionGrantedScopes } from "./scopes.mjs";
10
+ import { applyDefaultAccessTokenExpiry, generateCodeChallenge, getOAuth2Tokens, getPrimaryClientId } from "./utils.mjs";
11
+ import { authorizationCodeRequest, validateAuthorizationCode, validateToken } from "./validate-authorization-code.mjs";
8
12
  import { getJwks, verifyAccessToken, verifyJwsAccessToken } from "./verify.mjs";
9
- export { ASSERTION_SIGNING_ALGORITHMS, type AssertionSigningAlgorithm, CLIENT_ASSERTION_TYPE, type ClientAssertionConfig, type OAuth2Tokens, type OAuth2UserInfo, type OAuthProvider, type ProviderOptions, authorizationCodeRequest, clientCredentialsToken, clientCredentialsTokenRequest, createAuthorizationCodeRequest, createAuthorizationURL, createClientCredentialsTokenRequest, createRefreshAccessTokenRequest, generateCodeChallenge, getJwks, getOAuth2Tokens, getPrimaryClientId, refreshAccessToken, refreshAccessTokenRequest, resolveAssertionParams, signClientAssertion, validateAuthorizationCode, validateToken, verifyAccessToken, verifyJwsAccessToken };
13
+ import { supportsIdTokenSignIn, verifyProviderIdToken } from "./verify-id-token.mjs";
14
+ export { type AuthorizationURLResult, CLIENT_ASSERTION_TYPE, type ClientAssertionContext, type ClientAssertionGetter, type ClientAssertionGrantType, type GrantAuthority, type OAuth2Tokens, type OAuth2UserInfo, type OAuthIdTokenConfig, PRIVATE_KEY_JWT_SIGNING_ALGORITHMS, type PrivateKeyJwtClientAssertionGetterOptions, type PrivateKeyJwtSigningAlgorithm, type ProviderGrantAuthority, type ProviderOptions, RESERVED_AUTHORIZATION_PARAMS, RESERVED_AUTHORIZATION_PARAMS_SET, type TokenEndpointAuth, type TokenEndpointAuthMethod, type TokenEndpointSecretAuthentication, type UpstreamProvider, additionalAuthorizationParamsSchema, applyDefaultAccessTokenExpiry, authorizationCodeRequest, clientCredentialsToken, clientCredentialsTokenRequest, createAuthorizationURL, createPrivateKeyJwtClientAssertionGetter, decodeBasicCredentials, encodeBasicCredentials, generateCodeChallenge, getJwks, getOAuth2Tokens, getPrimaryClientId, includesGrantedScope, normalizeScopes, parseScopeField, readGrantedScopes, refreshAccessToken, refreshAccessTokenRequest, resolveClientAssertionParams, resolveRequestedScopes, signPrivateKeyJwtClientAssertion, supportsIdTokenSignIn, unionGrantedScopes, validateAuthorizationCode, validateToken, verifyAccessToken, verifyJwsAccessToken, verifyProviderIdToken };
@@ -1,8 +1,12 @@
1
- import { ASSERTION_SIGNING_ALGORITHMS, CLIENT_ASSERTION_TYPE, resolveAssertionParams, signClientAssertion } from "./client-assertion.mjs";
2
- import { clientCredentialsToken, clientCredentialsTokenRequest, createClientCredentialsTokenRequest } from "./client-credentials-token.mjs";
3
- import { generateCodeChallenge, getOAuth2Tokens, getPrimaryClientId } from "./utils.mjs";
4
- import { createAuthorizationURL } from "./create-authorization-url.mjs";
5
- import { createRefreshAccessTokenRequest, refreshAccessToken, refreshAccessTokenRequest } from "./refresh-access-token.mjs";
6
- import { authorizationCodeRequest, createAuthorizationCodeRequest, validateAuthorizationCode, validateToken } from "./validate-authorization-code.mjs";
1
+ import { includesGrantedScope, normalizeScopes, parseScopeField, readGrantedScopes, resolveRequestedScopes, unionGrantedScopes } from "./scopes.mjs";
2
+ import { applyDefaultAccessTokenExpiry, generateCodeChallenge, getOAuth2Tokens, getPrimaryClientId } from "./utils.mjs";
3
+ import { RESERVED_AUTHORIZATION_PARAMS, RESERVED_AUTHORIZATION_PARAMS_SET, createAuthorizationURL } from "./create-authorization-url.mjs";
4
+ import { additionalAuthorizationParamsSchema } from "./authorization-params.mjs";
5
+ import { decodeBasicCredentials, encodeBasicCredentials } from "./basic-credentials.mjs";
6
+ import { CLIENT_ASSERTION_TYPE, PRIVATE_KEY_JWT_SIGNING_ALGORITHMS, createPrivateKeyJwtClientAssertionGetter, resolveClientAssertionParams, signPrivateKeyJwtClientAssertion } from "./client-assertion.mjs";
7
+ import { clientCredentialsToken, clientCredentialsTokenRequest } from "./client-credentials-token.mjs";
8
+ import { refreshAccessToken, refreshAccessTokenRequest } from "./refresh-access-token.mjs";
9
+ import { authorizationCodeRequest, validateAuthorizationCode, validateToken } from "./validate-authorization-code.mjs";
7
10
  import { getJwks, verifyAccessToken, verifyJwsAccessToken } from "./verify.mjs";
8
- export { ASSERTION_SIGNING_ALGORITHMS, CLIENT_ASSERTION_TYPE, authorizationCodeRequest, clientCredentialsToken, clientCredentialsTokenRequest, createAuthorizationCodeRequest, createAuthorizationURL, createClientCredentialsTokenRequest, createRefreshAccessTokenRequest, generateCodeChallenge, getJwks, getOAuth2Tokens, getPrimaryClientId, refreshAccessToken, refreshAccessTokenRequest, resolveAssertionParams, signClientAssertion, validateAuthorizationCode, validateToken, verifyAccessToken, verifyJwsAccessToken };
11
+ import { supportsIdTokenSignIn, verifyProviderIdToken } from "./verify-id-token.mjs";
12
+ export { CLIENT_ASSERTION_TYPE, PRIVATE_KEY_JWT_SIGNING_ALGORITHMS, RESERVED_AUTHORIZATION_PARAMS, RESERVED_AUTHORIZATION_PARAMS_SET, additionalAuthorizationParamsSchema, applyDefaultAccessTokenExpiry, authorizationCodeRequest, clientCredentialsToken, clientCredentialsTokenRequest, createAuthorizationURL, createPrivateKeyJwtClientAssertionGetter, decodeBasicCredentials, encodeBasicCredentials, generateCodeChallenge, getJwks, getOAuth2Tokens, getPrimaryClientId, includesGrantedScope, normalizeScopes, parseScopeField, readGrantedScopes, refreshAccessToken, refreshAccessTokenRequest, resolveClientAssertionParams, resolveRequestedScopes, signPrivateKeyJwtClientAssertion, supportsIdTokenSignIn, unionGrantedScopes, validateAuthorizationCode, validateToken, verifyAccessToken, verifyJwsAccessToken, verifyProviderIdToken };
@@ -1,5 +1,53 @@
1
1
  import { Awaitable, LiteralString } from "../types/helper.mjs";
2
+ import { JWTVerifyGetKey } from "jose";
3
+
2
4
  //#region src/oauth2/oauth-provider.d.ts
5
+ /**
6
+ * id_token verification config for a social provider.
7
+ *
8
+ * Declares how a client-submitted id_token is verified. The shared verifier
9
+ * (`verifyProviderIdToken`) consumes this instead of each provider implementing its own
10
+ * boolean check, so verification is centralized and fail-closed: a provider without a config
11
+ * cannot accept a forged token by omission.
12
+ */
13
+ type OAuthIdTokenConfig = {
14
+ /**
15
+ * JWKS resolver used to verify the JWS signature. Accepts a jose
16
+ * `createRemoteJWKSet` resolver or a key-resolving function
17
+ * `(protectedHeader) => key`.
18
+ */
19
+ jwks: JWTVerifyGetKey; /** Expected `iss`. Omit for providers whose issuer varies per tenant. */
20
+ issuer?: (string | string[]) | undefined; /** Expected `aud`, usually the client ID. */
21
+ audience: string | string[]; /** Permitted JWS algorithms. Defaults to the token's `alg` header. */
22
+ algorithms?: string[] | undefined; /** Maximum token age passed to jose (e.g. `"1h"`). */
23
+ maxTokenAge?: string | undefined;
24
+ /**
25
+ * How the `nonce` claim is compared to the expected nonce.
26
+ * - `"exact"` (default): strict equality.
27
+ * - `"exact-or-sha256"`: matches the raw nonce or its SHA-256 hex digest (Apple).
28
+ */
29
+ nonceComparison?: ("exact" | "exact-or-sha256") | undefined;
30
+ /**
31
+ * Accept non-JWS (opaque) tokens without signature verification. Identity is then
32
+ * resolved by getUserInfo from the access token via the provider userinfo endpoint,
33
+ * which validates it (e.g. Facebook Graph access tokens).
34
+ */
35
+ allowOpaqueToken?: boolean | undefined;
36
+ /**
37
+ * Provider-specific claim check applied after the signature, issuer,
38
+ * audience, max-age, and nonce checks pass. Return `false` to reject the
39
+ * token. Used to enforce constraints the standard checks cannot express,
40
+ * e.g. Google's hosted-domain (`hd`) restriction. Omitted by providers
41
+ * that have no extra claim requirement.
42
+ */
43
+ verifyClaims?: ((claims: Record<string, unknown>) => boolean) | undefined;
44
+ } | {
45
+ /**
46
+ * Custom verifier for providers that cannot verify against a local JWKS, such as a
47
+ * remote verification endpoint (e.g. LINE).
48
+ */
49
+ verify: (token: string, nonce?: string) => Promise<boolean>;
50
+ };
3
51
  interface OAuth2Tokens {
4
52
  tokenType?: string | undefined;
5
53
  accessToken?: string | undefined;
@@ -21,8 +69,58 @@ type OAuth2UserInfo = {
21
69
  image?: string | undefined;
22
70
  emailVerified: boolean;
23
71
  };
24
- interface OAuthProvider<T extends Record<string, any> = Record<string, any>, O extends Record<string, any> = Partial<ProviderOptions>> {
72
+ /**
73
+ * The result of building a provider authorization URL.
74
+ *
75
+ * `requestedScopes` is the effective set of scopes encoded in the URL (the
76
+ * provider's built-in defaults + configured `options.scope` + per-request
77
+ * `scopes`, composed by `resolveRequestedScopes`). Callers persist it so the
78
+ * callback can fall back to the request when the provider omits `scope` from
79
+ * its token response (RFC 6749 §5.1).
80
+ */
81
+ interface AuthorizationURLResult {
82
+ url: URL;
83
+ requestedScopes: string[];
84
+ }
85
+ /**
86
+ * How much an RP trusts a provider's echoed token-response `scope` when
87
+ * persisting `account.grantedScopes`.
88
+ *
89
+ * - `"full-grant"`: the echo is the user's complete current grant, so the seam
90
+ * replaces the stored grant with it. This is the only path that may narrow
91
+ * the grant. Declare it only for providers whose token response reports the
92
+ * full combined grant, e.g. Google with `include_granted_scopes`.
93
+ * - `"projection"`: the echo is this request's subset, so the seam unions it
94
+ * onto the stored grant. The safe default for every provider.
95
+ * - `"absent-echo"`: the provider omitted `scope`, so the grant equals what was
96
+ * requested (RFC 6749 §5.1) and the seam unions the requested set. Resolved
97
+ * at runtime by the persistence seam, never declared by a provider.
98
+ *
99
+ * @see https://www.rfc-editor.org/rfc/rfc6749#section-5.1
100
+ */
101
+ type GrantAuthority = "full-grant" | "projection" | "absent-echo";
102
+ /**
103
+ * The authority a provider may declare for its own echoed scope. `"absent-echo"`
104
+ * is excluded because it is a runtime condition (an omitted echo), not a
105
+ * provider trait.
106
+ */
107
+ type ProviderGrantAuthority = Exclude<GrantAuthority, "absent-echo">;
108
+ interface UpstreamProvider<T extends Record<string, any> = Record<string, any>, O extends Record<string, any> = Partial<ProviderOptions>> {
25
109
  id: LiteralString;
110
+ /**
111
+ * The path the provider redirects back to, relative to the app base URL,
112
+ * e.g. `/callback/google`.
113
+ */
114
+ callbackPath: string;
115
+ /**
116
+ * How the persistence seam treats this provider's echoed token-response
117
+ * `scope`. Declare `"full-grant"` only when the echo is the user's complete
118
+ * current grant (e.g. Google with `include_granted_scopes`); otherwise the
119
+ * echo is unioned onto the stored grant.
120
+ *
121
+ * @default "projection"
122
+ */
123
+ grantAuthority?: ProviderGrantAuthority | undefined;
26
124
  createAuthorizationURL: (data: {
27
125
  state: string;
28
126
  codeVerifier: string;
@@ -30,7 +128,14 @@ interface OAuthProvider<T extends Record<string, any> = Record<string, any>, O e
30
128
  redirectURI: string;
31
129
  display?: string | undefined;
32
130
  loginHint?: string | undefined;
33
- }) => Awaitable<URL>;
131
+ /**
132
+ * Extra query parameters to append to the authorization URL.
133
+ * Providers forward these to the shared `createAuthorizationURL` helper,
134
+ * which drops any keys present in `RESERVED_AUTHORIZATION_PARAMS`
135
+ * before applying them.
136
+ */
137
+ additionalParams?: Record<string, string> | undefined;
138
+ }) => Awaitable<AuthorizationURLResult>;
34
139
  name: string;
35
140
  validateAuthorizationCode: (data: {
36
141
  code: string;
@@ -58,14 +163,12 @@ interface OAuthProvider<T extends Record<string, any> = Record<string, any>, O e
58
163
  * Custom function to refresh a token
59
164
  */
60
165
  refreshAccessToken?: ((refreshToken: string) => Promise<OAuth2Tokens>) | undefined;
61
- revokeToken?: ((token: string) => Promise<void>) | undefined;
62
166
  /**
63
- * Verify the id token
64
- * @param token - The id token
65
- * @param nonce - The nonce
66
- * @returns True if the id token is valid, false otherwise
167
+ * Declarative id_token verification config consumed by the shared
168
+ * `verifyProviderIdToken` verifier. Providers set this instead of implementing a boolean
169
+ * verify method, which keeps verification centralized and fail-closed.
67
170
  */
68
- verifyIdToken?: ((token: string, nonce?: string) => Promise<boolean>) | undefined;
171
+ idToken?: OAuthIdTokenConfig | undefined;
69
172
  /**
70
173
  * The expected issuer identifier for this provider (RFC 9207).
71
174
  * When set, the callback handler validates the `iss` query parameter
@@ -81,6 +184,17 @@ interface OAuthProvider<T extends Record<string, any> = Record<string, any>, O e
81
184
  * Disable sign up for new users.
82
185
  */
83
186
  disableSignUp?: boolean | undefined;
187
+ /**
188
+ * Accept callbacks that arrive without a `state` parameter. When true,
189
+ * the shared OAuth callback handler restarts the flow server-side with
190
+ * fresh `state` and PKCE instead of rejecting the request. Intended for
191
+ * providers that initiate OAuth without RP-side flow kickoff (e.g.
192
+ * Clever). Leave unset for any provider that always initiates from the
193
+ * RP.
194
+ *
195
+ * @default false
196
+ */
197
+ allowIdpInitiated?: boolean | undefined;
84
198
  /**
85
199
  * Options for the provider
86
200
  */
@@ -90,9 +204,10 @@ type ProviderOptions<Profile extends Record<string, any> = any> = {
90
204
  /**
91
205
  * The client ID of your application.
92
206
  *
93
- * This is usually a string but can be any type depending on the provider.
207
+ * Some providers accept multiple platform client IDs. The first entry is the
208
+ * primary client ID used for token endpoint client authentication.
94
209
  */
95
- clientId?: unknown | undefined;
210
+ clientId?: LiteralString | string[] | undefined;
96
211
  /**
97
212
  * The client secret of your application
98
213
  */
@@ -193,6 +308,29 @@ type ProviderOptions<Profile extends Record<string, any> = any> = {
193
308
  * @default false
194
309
  */
195
310
  overrideUserInfoOnSignIn?: boolean | undefined;
311
+ /**
312
+ * Require this provider's email to be verified before a session is created.
313
+ *
314
+ * When the provider reports the email as unverified, the user and account are
315
+ * still created/linked, but no session is issued: the OAuth callback redirects
316
+ * with `?error=email_not_verified` and id-token sign-in returns a `403`
317
+ * `EMAIL_NOT_VERIFIED`. A verification email is (re)sent per the
318
+ * `emailVerification` settings (`sendOnSignUp` / `sendOnSignIn`).
319
+ *
320
+ * The gate checks the local user's verification state, not the provider's
321
+ * claim on each request: a user already verified through another method (or a
322
+ * prior verified sign-in) keeps access even if the provider later reports the
323
+ * email as unverified.
324
+ *
325
+ * This is opt-in per provider and is independent of
326
+ * `emailAndPassword.requireEmailVerification`; enabling that does not gate
327
+ * social sign-in. Only enable it for providers that report a trustworthy
328
+ * `email_verified` signal: several providers always report the email as
329
+ * unverified, which would block every sign-in.
330
+ *
331
+ * @default false
332
+ */
333
+ requireEmailVerification?: boolean | undefined;
196
334
  };
197
335
  //#endregion
198
- export { OAuth2Tokens, OAuth2UserInfo, OAuthProvider, ProviderOptions };
336
+ export { AuthorizationURLResult, GrantAuthority, OAuth2Tokens, OAuth2UserInfo, OAuthIdTokenConfig, ProviderGrantAuthority, ProviderOptions, UpstreamProvider };