better-auth 1.7.2 → 1.7.4

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 (68) hide show
  1. package/dist/api/dispatch.mjs +4 -1
  2. package/dist/api/index.d.mts +6 -22
  3. package/dist/api/index.mjs +5 -1
  4. package/dist/api/routes/account.d.mts +1 -9
  5. package/dist/api/routes/account.mjs +0 -6
  6. package/dist/api/routes/callback.mjs +0 -2
  7. package/dist/api/routes/password.mjs +0 -2
  8. package/dist/api/routes/session.mjs +12 -5
  9. package/dist/api/routes/sign-in.d.mts +2 -2
  10. package/dist/api/routes/sign-in.mjs +1 -5
  11. package/dist/api/routes/sign-up.mjs +0 -2
  12. package/dist/api/routes/update-user.mjs +0 -2
  13. package/dist/api/to-auth-endpoints.mjs +2 -0
  14. package/dist/auth/base.mjs +13 -1
  15. package/dist/auth/trusted-origins.mjs +6 -4
  16. package/dist/client/config.d.mts +2 -0
  17. package/dist/client/config.mjs +1 -0
  18. package/dist/client/vue/index.d.mts +31 -20
  19. package/dist/client/vue/index.mjs +23 -5
  20. package/dist/context/create-context.mjs +2 -0
  21. package/dist/cookies/session-store.d.mts +0 -1
  22. package/dist/cookies/session-store.mjs +16 -5
  23. package/dist/db/adapter-kysely.mjs +1 -2
  24. package/dist/db/get-migration.d.mts +1 -0
  25. package/dist/db/get-migration.mjs +10 -32
  26. package/dist/db/internal-adapter.mjs +14 -17
  27. package/dist/db/schema.d.mts +0 -1
  28. package/dist/db/with-hooks.mjs +2 -1
  29. package/dist/index.mjs +0 -1
  30. package/dist/oauth2/account-key.mjs +1 -5
  31. package/dist/oauth2/link-account.d.mts +0 -1
  32. package/dist/oauth2/link-account.mjs +5 -11
  33. package/dist/package.mjs +1 -1
  34. package/dist/plugins/admin/routes.mjs +0 -3
  35. package/dist/plugins/device-authorization/index.d.mts +11 -11
  36. package/dist/plugins/email-otp/routes.mjs +0 -2
  37. package/dist/plugins/generic-oauth/index.mjs +14 -10
  38. package/dist/plugins/generic-oauth/providers/auth0.mjs +2 -4
  39. package/dist/plugins/generic-oauth/providers/keycloak.mjs +6 -9
  40. package/dist/plugins/generic-oauth/providers/line.mjs +0 -1
  41. package/dist/plugins/generic-oauth/providers/okta.mjs +6 -9
  42. package/dist/plugins/generic-oauth/providers/slack.mjs +0 -1
  43. package/dist/plugins/generic-oauth/types.d.mts +0 -9
  44. package/dist/plugins/haveibeenpwned/index.d.mts +9 -1
  45. package/dist/plugins/haveibeenpwned/index.mjs +31 -11
  46. package/dist/plugins/index.d.mts +3 -3
  47. package/dist/plugins/index.mjs +2 -2
  48. package/dist/plugins/last-login-method/index.mjs +1 -0
  49. package/dist/plugins/oauth-proxy/index.d.mts +17 -0
  50. package/dist/plugins/oauth-proxy/index.mjs +145 -99
  51. package/dist/plugins/one-tap/index.mjs +0 -1
  52. package/dist/plugins/open-api/generator.mjs +15 -1
  53. package/dist/plugins/open-api/index.mjs +0 -1
  54. package/dist/plugins/organization/has-permission.mjs +4 -2
  55. package/dist/plugins/phone-number/routes.mjs +0 -3
  56. package/dist/plugins/siwe/index.mjs +0 -3
  57. package/dist/plugins/test-utils/auth-helpers.mjs +8 -3
  58. package/dist/plugins/test-utils/index.d.mts +1 -1
  59. package/dist/plugins/test-utils/types.d.mts +10 -9
  60. package/dist/plugins/two-factor/client.d.mts +1 -0
  61. package/dist/plugins/two-factor/error-code.d.mts +1 -0
  62. package/dist/plugins/two-factor/error-code.mjs +1 -0
  63. package/dist/plugins/two-factor/index.d.mts +1 -0
  64. package/dist/plugins/two-factor/index.mjs +3 -2
  65. package/dist/state.d.mts +0 -13
  66. package/dist/test-utils/test-instance.mjs +10 -9
  67. package/package.json +12 -12
  68. package/dist/utils/index.mjs +0 -5
@@ -93,7 +93,6 @@ const genericOAuth = (options) => {
93
93
  return null;
94
94
  });
95
95
  if (discovered) {
96
- if (!discovered.issuer && !c.accountIssuer) throw new Error(`Provider "${c.providerId}": discovery did not return an issuer. Configure accountIssuer explicitly to establish a stable account namespace.`);
97
96
  authorizationUrl ??= discovered.authorization_endpoint;
98
97
  tokenUrl ??= discovered.token_endpoint;
99
98
  userInfoUrl ??= discovered.userinfo_endpoint;
@@ -106,7 +105,8 @@ const genericOAuth = (options) => {
106
105
  try {
107
106
  jwksUrl = new URL(discovered.jwks_uri, c.discoveryUrl);
108
107
  } catch {
109
- throw new Error(`Provider "${c.providerId}": invalid jwks_uri "${discovered.jwks_uri}" in discovery document.`);
108
+ ctx.logger.error(`Provider "${c.providerId}": invalid jwks_uri "${discovered.jwks_uri}" in discovery document. Provider skipped.`);
109
+ continue;
110
110
  }
111
111
  idTokenConfig = {
112
112
  jwks: createRemoteJWKSet(jwksUrl),
@@ -115,16 +115,24 @@ const genericOAuth = (options) => {
115
115
  algorithms: isOidc ? signingAlgs : void 0
116
116
  };
117
117
  }
118
- } else if (!c.accountIssuer) throw new Error(`Provider "${c.providerId}": discovery returned no valid data. Provider initialization stopped to keep its account issuer stable.`);
119
- else if (!authorizationUrl || !tokenUrl) ctx.logger.error(`Provider "${c.providerId}": discovery returned no data and no explicit endpoints configured. OAuth sign-in will fail for this provider.`);
118
+ }
119
+ if (!authorizationUrl || !tokenUrl && !c.getToken) {
120
+ ctx.logger.error(`Provider "${c.providerId}": discovery left no usable authorization endpoint or token exchange. Provider skipped.`);
121
+ continue;
122
+ }
123
+ }
124
+ if (c.requireIdTokenVerification && !idTokenConfig) {
125
+ if (c.discoveryUrl) {
126
+ ctx.logger.error(`Provider "${c.providerId}": requires verified ID tokens, but discovery did not provide a usable issuer and jwks_uri. Provider skipped.`);
127
+ continue;
128
+ }
129
+ throw new Error(`Provider "${c.providerId}": requires verified ID tokens, but discovery did not provide a usable issuer and jwks_uri.`);
120
130
  }
121
- if (c.requireIdTokenVerification && !idTokenConfig) throw new Error(`Provider "${c.providerId}": requires verified ID tokens, but discovery did not provide a usable issuer and jwks_uri.`);
122
131
  const tokenEndpointAuth = c.tokenEndpointAuth;
123
132
  if (c.clientSecret && isSecretlessTokenEndpointAuth(tokenEndpointAuth)) throw new Error(`Provider "${c.providerId}": tokenEndpointAuth.method "${tokenEndpointAuth?.method}" cannot be combined with clientSecret`);
124
133
  if (!c.clientSecret && isClientSecretTokenEndpointAuth(tokenEndpointAuth)) throw new Error(`Provider "${c.providerId}": tokenEndpointAuth.method "${tokenEndpointAuth?.method}" requires clientSecret`);
125
134
  if (!c.clientSecret && !tokenEndpointAuth && c.authentication === "basic") throw new Error(`Provider "${c.providerId}": authentication "basic" requires clientSecret`);
126
135
  const accountSubject = c.accountSubject;
127
- const accountIssuer = c.accountIssuer;
128
136
  const provider = {
129
137
  id: c.providerId,
130
138
  name: c.name ?? c.providerId,
@@ -137,10 +145,6 @@ const genericOAuth = (options) => {
137
145
  });
138
146
  return isOidc ? genericProfile.sub ?? "" : genericProfile.id ?? "";
139
147
  },
140
- accountIssuer: typeof accountIssuer === "function" ? ({ tokens, profile }) => accountIssuer({
141
- tokens,
142
- profile
143
- }) : accountIssuer ?? issuer,
144
148
  idToken: idTokenConfig,
145
149
  requiresIdTokenNonce: idTokenConfig !== void 0 && c.disableIdTokenNonceBinding !== true,
146
150
  allowIdpInitiated: c.allowIdpInitiated,
@@ -27,12 +27,10 @@ function auth0(options) {
27
27
  "profile",
28
28
  "email"
29
29
  ];
30
- const domain = options.domain.replace(/^https?:\/\//, "").replace(/\/+$/, "");
31
- const discoveryUrl = `https://${domain}/.well-known/openid-configuration`;
30
+ const domainUrl = options.domain.startsWith("http://") || options.domain.startsWith("https://") ? options.domain : `https://${options.domain}`;
32
31
  return {
33
32
  providerId: "auth0",
34
- accountIssuer: `https://${domain}/`,
35
- discoveryUrl,
33
+ discoveryUrl: `https://${new URL(domainUrl).host}/.well-known/openid-configuration`,
36
34
  clientId: options.clientId,
37
35
  clientSecret: options.clientSecret,
38
36
  tokenEndpointAuth: options.tokenEndpointAuth,
@@ -22,20 +22,17 @@
22
22
  * ```
23
23
  */
24
24
  function keycloak(options) {
25
- const defaultScopes = [
26
- "openid",
27
- "profile",
28
- "email"
29
- ];
30
- const issuer = options.issuer.replace(/\/$/, "");
31
25
  return {
32
26
  providerId: "keycloak",
33
- accountIssuer: issuer,
34
- discoveryUrl: `${issuer}/.well-known/openid-configuration`,
27
+ discoveryUrl: `${options.issuer.replace(/\/$/, "")}/.well-known/openid-configuration`,
35
28
  clientId: options.clientId,
36
29
  clientSecret: options.clientSecret,
37
30
  tokenEndpointAuth: options.tokenEndpointAuth,
38
- scopes: options.scopes ?? defaultScopes,
31
+ scopes: options.scopes ?? [
32
+ "openid",
33
+ "profile",
34
+ "email"
35
+ ],
39
36
  redirectURI: options.redirectURI,
40
37
  endSessionEndpoint: options.endSessionEndpoint,
41
38
  postLogoutRedirectURI: options.postLogoutRedirectURI,
@@ -71,7 +71,6 @@ function line(options) {
71
71
  return {
72
72
  providerId: options.providerId ?? "line",
73
73
  accountSubject: ({ profile }) => profile.sub ?? "",
74
- accountIssuer: "https://access.line.me",
75
74
  authorizationUrl,
76
75
  tokenUrl,
77
76
  userInfoUrl,
@@ -22,20 +22,17 @@
22
22
  * ```
23
23
  */
24
24
  function okta(options) {
25
- const defaultScopes = [
26
- "openid",
27
- "profile",
28
- "email"
29
- ];
30
- const issuer = options.issuer.replace(/\/$/, "");
31
25
  return {
32
26
  providerId: "okta",
33
- accountIssuer: issuer,
34
- discoveryUrl: `${issuer}/.well-known/openid-configuration`,
27
+ discoveryUrl: `${options.issuer.replace(/\/$/, "")}/.well-known/openid-configuration`,
35
28
  clientId: options.clientId,
36
29
  clientSecret: options.clientSecret,
37
30
  tokenEndpointAuth: options.tokenEndpointAuth,
38
- scopes: options.scopes ?? defaultScopes,
31
+ scopes: options.scopes ?? [
32
+ "openid",
33
+ "profile",
34
+ "email"
35
+ ],
39
36
  redirectURI: options.redirectURI,
40
37
  endSessionEndpoint: options.endSessionEndpoint,
41
38
  postLogoutRedirectURI: options.postLogoutRedirectURI,
@@ -41,7 +41,6 @@ function slack(options) {
41
41
  return {
42
42
  providerId: "slack",
43
43
  accountSubject: ({ profile }) => profile.sub ?? "",
44
- accountIssuer: "https://slack.com",
45
44
  authorizationUrl: "https://slack.com/openid/connect/authorize",
46
45
  tokenUrl: "https://slack.com/api/openid.connect.token",
47
46
  userInfoUrl: "https://slack.com/api/openid.connect.userInfo",
@@ -36,15 +36,6 @@ interface GenericOAuthConfig<ID extends string = string> {
36
36
  * mapping cannot redefine provider identity.
37
37
  */
38
38
  accountSubject?: ((context: OAuthAccountKeyContext<GenericOAuthUserInfo>) => Awaitable<string | number>) | undefined;
39
- /**
40
- * Stable issuer namespace paired with the provider account ID.
41
- *
42
- * Discovery providers use the discovered issuer by default. Set this for
43
- * providers without discovery, provider aliases that share one identity
44
- * namespace, or tenant-specific issuers derived from verified provider data.
45
- * The resolver must not use unverified request input.
46
- */
47
- accountIssuer?: string | ((context: OAuthAccountKeyContext<GenericOAuthUserInfo>) => Awaitable<string>) | undefined;
48
39
  /**
49
40
  * URL to fetch OAuth 2.0 configuration.
50
41
  * If provided, the authorization and token endpoints will be fetched from this URL.
@@ -9,6 +9,14 @@ declare module "@better-auth/core" {
9
9
  };
10
10
  }
11
11
  }
12
+ /**
13
+ * Checks whether a password appears in the Have I Been Pwned password corpus.
14
+ * Only the first five characters of its SHA-1 hash are sent to the service.
15
+ *
16
+ * @returns Whether the password has been compromised.
17
+ * @throws {APIError} When the password could not be checked.
18
+ */
19
+ declare function isPasswordCompromised(password: string): Promise<boolean>;
12
20
  interface HaveIBeenPwnedOptions {
13
21
  /**
14
22
  * Custom error message shown when a compromised password is detected.
@@ -52,4 +60,4 @@ declare const haveIBeenPwned: (options?: HaveIBeenPwnedOptions | undefined) => {
52
60
  };
53
61
  };
54
62
  //#endregion
55
- export { HaveIBeenPwnedOptions, haveIBeenPwned };
63
+ export { HaveIBeenPwnedOptions, haveIBeenPwned, isPasswordCompromised };
@@ -7,26 +7,46 @@ import { createHash } from "@better-auth/utils/hash";
7
7
  import { betterFetch } from "@better-fetch/fetch";
8
8
  //#region src/plugins/haveibeenpwned/index.ts
9
9
  const ERROR_CODES = defineErrorCodes({ PASSWORD_COMPROMISED: "The password you entered has been compromised. Please choose a different password." });
10
- async function checkPasswordCompromise(password, customMessage) {
11
- if (!password) return;
12
- const sha1Hash = (await createHash("SHA-1", "hex").digest(password)).toUpperCase();
13
- const prefix = sha1Hash.substring(0, 5);
14
- const suffix = sha1Hash.substring(5);
10
+ function getPasswordCompromiseCount(response, hashSuffix) {
11
+ const matchingEntryPrefix = `${hashSuffix.toUpperCase()}:`;
12
+ for (const line of response.split(/\r?\n/)) {
13
+ if (line.slice(0, matchingEntryPrefix.length).toUpperCase() !== matchingEntryPrefix) continue;
14
+ const compromiseCountText = line.slice(matchingEntryPrefix.length);
15
+ const compromiseCount = Number(compromiseCountText);
16
+ if (!(Number.isSafeInteger(compromiseCount) && compromiseCount >= 0 && String(compromiseCount) === compromiseCountText)) throw new Error("Invalid password compromise count");
17
+ return compromiseCount;
18
+ }
19
+ return 0;
20
+ }
21
+ /**
22
+ * Checks whether a password appears in the Have I Been Pwned password corpus.
23
+ * Only the first five characters of its SHA-1 hash are sent to the service.
24
+ *
25
+ * @returns Whether the password has been compromised.
26
+ * @throws {APIError} When the password could not be checked.
27
+ */
28
+ async function isPasswordCompromised(password) {
15
29
  try {
30
+ const sha1Hash = (await createHash("SHA-1", "hex").digest(password)).toUpperCase();
31
+ const prefix = sha1Hash.substring(0, 5);
32
+ const suffix = sha1Hash.substring(5);
16
33
  const { data, error } = await betterFetch(`https://api.pwnedpasswords.com/range/${prefix}`, { headers: {
17
34
  "Add-Padding": "true",
18
35
  "User-Agent": "BetterAuth Password Checker"
19
36
  } });
20
37
  if (error) throw new APIError("INTERNAL_SERVER_ERROR", { message: `Failed to check password. Status: ${error.status}` });
21
- if (data.split("\n").some((line) => line.split(":")[0].toUpperCase() === suffix.toUpperCase())) throw APIError.from("BAD_REQUEST", {
22
- message: customMessage || ERROR_CODES.PASSWORD_COMPROMISED.message,
23
- code: ERROR_CODES.PASSWORD_COMPROMISED.code
24
- });
38
+ return getPasswordCompromiseCount(data, suffix) > 0;
25
39
  } catch (error) {
26
40
  if (isAPIError(error)) throw error;
27
41
  throw new APIError("INTERNAL_SERVER_ERROR", { message: "Failed to check password. Please try again later." });
28
42
  }
29
43
  }
44
+ async function rejectCompromisedPassword(password, customMessage) {
45
+ if (await isPasswordCompromised(password)) throw APIError.from("BAD_REQUEST", {
46
+ message: customMessage || ERROR_CODES.PASSWORD_COMPROMISED.message,
47
+ code: ERROR_CODES.PASSWORD_COMPROMISED.code
48
+ });
49
+ }
30
50
  const haveIBeenPwned = (options) => {
31
51
  const paths = options?.paths || [
32
52
  "/sign-up/email",
@@ -48,7 +68,7 @@ const haveIBeenPwned = (options) => {
48
68
  if (options?.enabled === false) return originalHash(password);
49
69
  const c = getCurrentAuthEndpointContext();
50
70
  if (!c.path || !paths.includes(c.path)) return originalHash(password);
51
- await checkPasswordCompromise(password, options?.customPasswordCompromisedMessage);
71
+ await rejectCompromisedPassword(password, options?.customPasswordCompromisedMessage);
52
72
  return originalHash(password);
53
73
  }
54
74
  } } };
@@ -58,4 +78,4 @@ const haveIBeenPwned = (options) => {
58
78
  };
59
79
  };
60
80
  //#endregion
61
- export { haveIBeenPwned };
81
+ export { haveIBeenPwned, isPasswordCompromised };
@@ -31,7 +31,7 @@ import { PatreonOptions, patreon } from "./generic-oauth/providers/patreon.mjs";
31
31
  import { SlackOptions, slack } from "./generic-oauth/providers/slack.mjs";
32
32
  import { YandexOptions, yandex } from "./generic-oauth/providers/yandex.mjs";
33
33
  import { BaseOAuthProviderOptions, genericOAuth } from "./generic-oauth/index.mjs";
34
- import { HaveIBeenPwnedOptions, haveIBeenPwned } from "./haveibeenpwned/index.mjs";
34
+ import { HaveIBeenPwnedOptions, haveIBeenPwned, isPasswordCompromised } from "./haveibeenpwned/index.mjs";
35
35
  import { JWKOptions, JWSAlgorithms, Jwk, JwtOptions, ResolvedSigningKey } from "./jwt/types.mjs";
36
36
  import { getJwtToken, resolveSigningKey, signJWT } from "./jwt/sign.mjs";
37
37
  import { createJwk, generateExportedKeyPair, toExpJWT } from "./jwt/utils.mjs";
@@ -53,7 +53,7 @@ import { OpenAPIOptions, openAPI } from "./open-api/index.mjs";
53
53
  import { PhoneNumberOptions, UserWithPhoneNumber } from "./phone-number/types.mjs";
54
54
  import { phoneNumber } from "./phone-number/index.mjs";
55
55
  import { SIWEPluginOptions, siwe } from "./siwe/index.mjs";
56
- import { LoginResult, TestCookie, TestHelpers, TestUtilsOptions } from "./test-utils/types.mjs";
56
+ import { LoginResult, TestAuthOptions, TestCookie, TestHelpers, TestUtilsOptions } from "./test-utils/types.mjs";
57
57
  import { testUtils } from "./test-utils/index.mjs";
58
58
  import { BackupCodeOptions, backupCode2fa, encodeBackupCodes, generateBackupCodes, getBackupCodes, verifyBackupCode } from "./two-factor/backup-codes/index.mjs";
59
59
  import { OTPOptions, otp2fa } from "./two-factor/otp/index.mjs";
@@ -66,4 +66,4 @@ import { USERNAME_ERROR_CODES } from "./username/error-codes.mjs";
66
66
  import { UsernameOptions, UsernamePlugin, UsernamePluginWithoutDisplayUsername, username } from "./username/index.mjs";
67
67
  import { hasPermission } from "./organization/has-permission.mjs";
68
68
  import { DefaultOrganizationPlugin, DynamicAccessControlEndpoints, OrganizationCreator, OrganizationEndpoints, OrganizationPlugin, TeamEndpoints, organization, parseRoles } from "./organization/organization.mjs";
69
- export { AccessControl, AdminOptions, AnonymousOptions, AnonymousSession, ArrayElement, Auth0Options, AuthorizeResponse, BackupCodeOptions, BaseCaptchaOptions, BaseOAuthProviderOptions, BearerOptions, CaptchaFoxOptions, CaptchaOptions, CloudflareTurnstileOptions, CustomSessionPluginOptions, DefaultOrganizationPlugin, DeviceAuthorizationGrant, DeviceAuthorizationGrantAuthorization, DeviceAuthorizationOptions, DeviceAuthorizationPluginOptions, DeviceAuthorizationRequest, DeviceCode, DeviceCodeRedemptionAuthorization, DeviceCodeRedemptionResult, DynamicAccessControlEndpoints, MULTI_SESSION_ERROR_CODES as ERROR_CODES, EmailOTPOptions, ExactRoleStatements, FieldSchema, GenericOAuthConfig, GenericOAuthOptions, GenericOAuthUserInfo, GoogleRecaptchaOptions, GumroadOptions, HCaptchaOptions, HIDE_METADATA, HaveIBeenPwnedOptions, HubSpotOptions, InferAdminRolesFromOption, InferInvitation, InferMember, InferOptionSchema, InferOrganization, InferOrganizationRolesFromOption, InferOrganizationZodRolesFromOption, InferPluginContext, InferPluginErrorCodes, InferPluginIDs, InferTeam, Invitation, InvitationInput, InvitationStatus, JWKOptions, JWSAlgorithms, Jwk, JwtOptions, KeycloakOptions, LastLoginMethodOptions, LineOptions, LoginResult, MagicLinkOptions, Member, MemberInput, MicrosoftEntraIdOptions, MultiSessionConfig, OAUTH_POPUP_COMPLETE_SCRIPT, OAUTH_POPUP_DATA_ELEMENT_ID, OAUTH_POPUP_ERROR_CODES, OAUTH_POPUP_MESSAGE_TYPE, OAUTH_POPUP_SCRIPT_CSP_HASH, OAuthPopupData, OAuthPopupMessage, OAuthProxyOptions, OTPOptions, OktaOptions, OneTapOptions, OneTimeTokenOptions, OpenAPIModelSchema, OpenAPIOptions, OpenAPIParameter, OpenAPISchema, Organization, OrganizationCreator, OrganizationEndpoints, OrganizationInput, OrganizationOptions, OrganizationPlugin, OrganizationRole, OrganizationSchema, POPUP_MARKER_COOKIE, Path, PatreonOptions, PhoneNumberOptions, Provider, ResolvedSigningKey, Role, RoleAuthorizeRequest, RoleInput, RoleStatements, SIWEPluginOptions, SessionWithImpersonatedBy, SlackOptions, Statements, SubArray, Subset, TOTPOptions, TWO_FACTOR_ERROR_CODES, Team, TeamEndpoints, TeamInput, TeamMember, TeamMemberInput, TestCookie, TestHelpers, TestUtilsOptions, TimeString, TwoFactorOptions, TwoFactorProvider, TwoFactorTable, USERNAME_ERROR_CODES, UserWithAnonymous, UserWithPhoneNumber, UserWithRole, UserWithTwoFactor, UsernameOptions, UsernamePlugin, UsernamePluginWithoutDisplayUsername, YandexOptions, admin, anonymous, auth0, backupCode2fa, bearer, captcha, createAccessControl, createJwk, customSession, defaultRolesSchema, deviceAuthorization, deviceAuthorizationOptionsSchema, emailOTP, encodeBackupCodes, generateBackupCodes, generateExportedKeyPair, generator, genericOAuth, getBackupCodes, getJwtToken, getOrgAdapter, gumroad, hasPermission, haveIBeenPwned, hubspot, invitationSchema, invitationStatus, jwt, keycloak, lastLoginMethod, line, magicLink, memberSchema, microsoftEntraId, ms, multiSession, oAuthProxy, oauthPopup, okta, oneTap, oneTimeToken, openAPI, organization, organizationRoleSchema, organizationSchema, otp2fa, parseRoles, patreon, phoneNumber, redeemDeviceCode, resolveSigningKey, role, roleSchema, sec, signJWT, siwe, slack, teamMemberSchema, teamSchema, testUtils, toExpJWT, totp2fa, twoFactor, twoFactorClient, username, verifyBackupCode, verifyJWT, yandex };
69
+ export { AccessControl, AdminOptions, AnonymousOptions, AnonymousSession, ArrayElement, Auth0Options, AuthorizeResponse, BackupCodeOptions, BaseCaptchaOptions, BaseOAuthProviderOptions, BearerOptions, CaptchaFoxOptions, CaptchaOptions, CloudflareTurnstileOptions, CustomSessionPluginOptions, DefaultOrganizationPlugin, DeviceAuthorizationGrant, DeviceAuthorizationGrantAuthorization, DeviceAuthorizationOptions, DeviceAuthorizationPluginOptions, DeviceAuthorizationRequest, DeviceCode, DeviceCodeRedemptionAuthorization, DeviceCodeRedemptionResult, DynamicAccessControlEndpoints, MULTI_SESSION_ERROR_CODES as ERROR_CODES, EmailOTPOptions, ExactRoleStatements, FieldSchema, GenericOAuthConfig, GenericOAuthOptions, GenericOAuthUserInfo, GoogleRecaptchaOptions, GumroadOptions, HCaptchaOptions, HIDE_METADATA, HaveIBeenPwnedOptions, HubSpotOptions, InferAdminRolesFromOption, InferInvitation, InferMember, InferOptionSchema, InferOrganization, InferOrganizationRolesFromOption, InferOrganizationZodRolesFromOption, InferPluginContext, InferPluginErrorCodes, InferPluginIDs, InferTeam, Invitation, InvitationInput, InvitationStatus, JWKOptions, JWSAlgorithms, Jwk, JwtOptions, KeycloakOptions, LastLoginMethodOptions, LineOptions, LoginResult, MagicLinkOptions, Member, MemberInput, MicrosoftEntraIdOptions, MultiSessionConfig, OAUTH_POPUP_COMPLETE_SCRIPT, OAUTH_POPUP_DATA_ELEMENT_ID, OAUTH_POPUP_ERROR_CODES, OAUTH_POPUP_MESSAGE_TYPE, OAUTH_POPUP_SCRIPT_CSP_HASH, OAuthPopupData, OAuthPopupMessage, OAuthProxyOptions, OTPOptions, OktaOptions, OneTapOptions, OneTimeTokenOptions, OpenAPIModelSchema, OpenAPIOptions, OpenAPIParameter, OpenAPISchema, Organization, OrganizationCreator, OrganizationEndpoints, OrganizationInput, OrganizationOptions, OrganizationPlugin, OrganizationRole, OrganizationSchema, POPUP_MARKER_COOKIE, Path, PatreonOptions, PhoneNumberOptions, Provider, ResolvedSigningKey, Role, RoleAuthorizeRequest, RoleInput, RoleStatements, SIWEPluginOptions, SessionWithImpersonatedBy, SlackOptions, Statements, SubArray, Subset, TOTPOptions, TWO_FACTOR_ERROR_CODES, Team, TeamEndpoints, TeamInput, TeamMember, TeamMemberInput, TestAuthOptions, TestCookie, TestHelpers, TestUtilsOptions, TimeString, TwoFactorOptions, TwoFactorProvider, TwoFactorTable, USERNAME_ERROR_CODES, UserWithAnonymous, UserWithPhoneNumber, UserWithRole, UserWithTwoFactor, UsernameOptions, UsernamePlugin, UsernamePluginWithoutDisplayUsername, YandexOptions, admin, anonymous, auth0, backupCode2fa, bearer, captcha, createAccessControl, createJwk, customSession, defaultRolesSchema, deviceAuthorization, deviceAuthorizationOptionsSchema, emailOTP, encodeBackupCodes, generateBackupCodes, generateExportedKeyPair, generator, genericOAuth, getBackupCodes, getJwtToken, getOrgAdapter, gumroad, hasPermission, haveIBeenPwned, hubspot, invitationSchema, invitationStatus, isPasswordCompromised, jwt, keycloak, lastLoginMethod, line, magicLink, memberSchema, microsoftEntraId, ms, multiSession, oAuthProxy, oauthPopup, okta, oneTap, oneTimeToken, openAPI, organization, organizationRoleSchema, organizationSchema, otp2fa, parseRoles, patreon, phoneNumber, redeemDeviceCode, resolveSigningKey, role, roleSchema, sec, signJWT, siwe, slack, teamMemberSchema, teamSchema, testUtils, toExpJWT, totp2fa, twoFactor, twoFactorClient, username, verifyBackupCode, verifyJWT, yandex };
@@ -25,7 +25,7 @@ import { patreon } from "./generic-oauth/providers/patreon.mjs";
25
25
  import { slack } from "./generic-oauth/providers/slack.mjs";
26
26
  import { yandex } from "./generic-oauth/providers/yandex.mjs";
27
27
  import { genericOAuth } from "./generic-oauth/index.mjs";
28
- import { haveIBeenPwned } from "./haveibeenpwned/index.mjs";
28
+ import { haveIBeenPwned, isPasswordCompromised } from "./haveibeenpwned/index.mjs";
29
29
  import { createJwk, generateExportedKeyPair, toExpJWT } from "./jwt/utils.mjs";
30
30
  import { getJwtToken, resolveSigningKey, signJWT } from "./jwt/sign.mjs";
31
31
  import { verifyJWT } from "./jwt/verify.mjs";
@@ -46,4 +46,4 @@ import { siwe } from "./siwe/index.mjs";
46
46
  import { testUtils } from "./test-utils/index.mjs";
47
47
  import { twoFactor } from "./two-factor/index.mjs";
48
48
  import { username } from "./username/index.mjs";
49
- export { MULTI_SESSION_ERROR_CODES as ERROR_CODES, HIDE_METADATA, OAUTH_POPUP_COMPLETE_SCRIPT, OAUTH_POPUP_DATA_ELEMENT_ID, OAUTH_POPUP_ERROR_CODES, OAUTH_POPUP_MESSAGE_TYPE, OAUTH_POPUP_SCRIPT_CSP_HASH, POPUP_MARKER_COOKIE, TWO_FACTOR_ERROR_CODES, USERNAME_ERROR_CODES, admin, anonymous, auth0, bearer, captcha, createAccessControl, createJwk, customSession, deviceAuthorization, deviceAuthorizationOptionsSchema, emailOTP, generateExportedKeyPair, genericOAuth, getJwtToken, getOrgAdapter, gumroad, hasPermission, haveIBeenPwned, hubspot, jwt, keycloak, lastLoginMethod, line, magicLink, microsoftEntraId, multiSession, oAuthProxy, oauthPopup, okta, oneTap, oneTimeToken, openAPI, organization, parseRoles, patreon, phoneNumber, redeemDeviceCode, resolveSigningKey, role, signJWT, siwe, slack, testUtils, toExpJWT, twoFactor, twoFactorClient, username, verifyJWT, yandex };
49
+ export { MULTI_SESSION_ERROR_CODES as ERROR_CODES, HIDE_METADATA, OAUTH_POPUP_COMPLETE_SCRIPT, OAUTH_POPUP_DATA_ELEMENT_ID, OAUTH_POPUP_ERROR_CODES, OAUTH_POPUP_MESSAGE_TYPE, OAUTH_POPUP_SCRIPT_CSP_HASH, POPUP_MARKER_COOKIE, TWO_FACTOR_ERROR_CODES, USERNAME_ERROR_CODES, admin, anonymous, auth0, bearer, captcha, createAccessControl, createJwk, customSession, deviceAuthorization, deviceAuthorizationOptionsSchema, emailOTP, generateExportedKeyPair, genericOAuth, getJwtToken, getOrgAdapter, gumroad, hasPermission, haveIBeenPwned, hubspot, isPasswordCompromised, jwt, keycloak, lastLoginMethod, line, magicLink, microsoftEntraId, multiSession, oAuthProxy, oauthPopup, okta, oneTap, oneTimeToken, openAPI, organization, parseRoles, patreon, phoneNumber, redeemDeviceCode, resolveSigningKey, role, signJWT, siwe, slack, testUtils, toExpJWT, twoFactor, twoFactorClient, username, verifyJWT, yandex };
@@ -13,6 +13,7 @@ const lastLoginMethod = (userConfig) => {
13
13
  if (path.includes("siwe")) return "siwe";
14
14
  if (path.includes("/passkey/verify-authentication")) return "passkey";
15
15
  if (path.startsWith("/magic-link/verify")) return "magic-link";
16
+ if (path === "/sign-in/email-otp") return "email-otp";
16
17
  return null;
17
18
  };
18
19
  const getResolveContext = (ctx) => {
@@ -58,6 +58,10 @@ declare const oAuthProxy: <O extends OAuthProxyOptions>(opts?: O) => {
58
58
  version: string;
59
59
  options: NoInfer<O>;
60
60
  endpoints: {
61
+ /**
62
+ * @deprecated OAuth proxy callbacks now use `/callback/:id/oauth-proxy`.
63
+ * This endpoint will be removed in the next minor release.
64
+ */
61
65
  oAuthProxy: _$better_call0.StrictEndpoint<"/oauth-proxy-callback", {
62
66
  method: "GET";
63
67
  operationId: string;
@@ -69,6 +73,7 @@ declare const oAuthProxy: <O extends OAuthProxyOptions>(opts?: O) => {
69
73
  metadata: {
70
74
  openapi: {
71
75
  operationId: string;
76
+ deprecated: boolean;
72
77
  description: string;
73
78
  parameters: ({
74
79
  in: "query";
@@ -97,6 +102,18 @@ declare const oAuthProxy: <O extends OAuthProxyOptions>(opts?: O) => {
97
102
  };
98
103
  };
99
104
  }, never>;
105
+ oAuthProxyCompletion: _$better_call0.StrictEndpoint<"/callback/:id/oauth-proxy", {
106
+ method: "GET";
107
+ operationId: string;
108
+ query: z.ZodObject<{
109
+ callbackURL: z.ZodString;
110
+ profile: z.ZodOptional<z.ZodString>;
111
+ }, z.core.$strip>;
112
+ use: _$better_call0.Middleware<_$better_call0.MiddlewareOptions, (inputContext: _$better_call0.MiddlewareInputContext<_$better_call0.MiddlewareOptions>) => Promise<void>>[];
113
+ metadata: {
114
+ scope: "http";
115
+ };
116
+ }, never>;
100
117
  };
101
118
  hooks: {
102
119
  before: {