Changelog

All changes, fixes, and updates

Every release shipped to Better Auth, straight from GitHub.

CHANGELOG

better-auth

Bug Fixes

  • Fixed Google One Tap authenticating the wrong user when the presented Google account was already linked to a different local user.
  • Fixed null values being rejected for optional fields in the generated database schema (#9841)
  • Fixed getSessionCookie to prefer the __Secure- prefixed cookie over a non-secure leftover, preventing a stale cookie from shadowing the current session (#9806)
  • Fixed redirect URI validation to work on all supported runtimes and to reject URIs containing a fragment component per RFC 6749 §3.1.2 (#9845)
  • Fixed organization invitation verification to restore the normal emailed-invitation flow while enforcing stricter email verification for externally controlled or predictable invitation IDs (#9877)

For detailed changes, see CHANGELOG

@better-auth/sso

Bug Fixes

  • Fixed SAML Single Logout leaving the user signed in due to the logout handlers matching the session by ID instead of token.

For detailed changes, see CHANGELOG

Contributors

Thanks to everyone who contributed to this release:

@bytaesu, @gustavovalverde

Full changelog: v1.6.13...v1.6.14

better-auth

Features

  • Added support for server-side accountInfo calls with an optional userId parameter, allowing trusted callers to read provider profiles without constructing session headers (#9813)

Bug Fixes

  • Clarified that viewBackupCodes is a server-only function not accessible via HTTP in its API documentation (#9822)
  • Fixed Google One Tap authenticating the wrong user when the presented Google account is already linked to a different local user, by resolving identity through the shared OAuth path
  • Fixed storeStateStrategy defaulting to "cookie" instead of "database" when only secondaryStorage is configured, preventing oversized-cookie errors on platforms like AWS Lambda (#9591)
  • Fixed updateUserInfoOnLink not being applied when linking accounts through the standard OAuth redirect flow (#8758)
  • Fixed oidc-provider and mcp plugins accepting invalid redirect_uri schemes such as javascript: and data: (#9838)
  • Fixed organization logo not accepting null, preventing users from clearing an existing logo on create and update (#9842)

For detailed changes, see CHANGELOG

@better-auth/sso

Bug Fixes

  • Fixed SAML Single Logout leaving the user signed in due to session deletion matching on row ID instead of session token
  • Fixed ambiguous internalAdapter helper methods that could silently match the wrong account or wipe all sessions for a user (#9818)
  • Fixed a high-severity XML injection vulnerability in signed SAML assertions by updating samlify to 2.13.1 (GHSA-34r5-q4jw-r36m) (#9821)

For detailed changes, see CHANGELOG

@better-auth/api-key

Bug Fixes

  • Fixed verifyApiKey rejecting keys created under a non-default configId when the request omitted configId (#9794)

For detailed changes, see CHANGELOG

@better-auth/core

Bug Fixes

  • Fixed a silent failure in consumeOne when an adapter's deleteMany returned a non-numeric value, now surfacing a clear error (#9831)

For detailed changes, see CHANGELOG

@better-auth/expo

Bug Fixes

  • Fixed sign-in being lost on Expo when a provider issues large tokens, by splitting oversized account cookies across multiple storage keys (#9815)

For detailed changes, see CHANGELOG

@better-auth/oauth-provider

Bug Fixes

  • Fixed POST /oauth2/register bypassing the clientPrivileges create check, allowing unauthorized dynamic client registration (#9837)

For detailed changes, see CHANGELOG

Contributors

Thanks to everyone who contributed to this release:

@bytaesu, @gustavovalverde, @Vishesh-Verma-07

Full changelog: v1.6.12...v1.6.13

better-auth

Bug Fixes

  • Fixed field index ordering in getMigration migrations. (#9691)
  • Fixed synthetic user construction to exclude extra fields. (#9347)
  • Fixed session cookie refresh headers not being forwarded when resolving sessions. (#9667)
  • Fixed changeEmail to return an error when emailVerification.sendVerificationEmail is missing, and URL-encoded callbackURL in verify-email links. (#9614)
  • Fixed callbackURL URL-encoding in verify-email links for OAuth account linking and username sign-in. (#9792)
  • Fixed role.authorize to reject empty action lists and correctly evaluate OR conditions on unknown resources. (#9603)
  • Fixed missing exports of AdminClientOptions and OrganizationClientOptions. (#9642)
  • Fixed email OTP sign-in failing with captcha errors under default captcha settings. (#9596)
  • Fixed parseJSON to properly decode escape sequences in quoted strings. (#9617)
  • Fixed cookie parsing to tolerate missing spaces after `
  • Fixed getTrustedOrigins to respect the dynamic baseURL protocol option. (#9644)
  • Fixed request mutation by cloning the request before passing it to the sendVerificationEmail callback. (#9619)
  • Added accessTokenExpiresIn config option to genericOAuth for providers that omit expires_in in their token response. (#9799)
  • Fixed oauth-proxy to forward specific error codes instead of collapsing all errors into user_creation_failed. (#9723)
  • Fixed oauth-proxy flows failing with state_mismatch when production and preview environments use different secrets. (#9385)
  • Fixed OAuth callback errors to forward specific error codes (state_not_found, state_invalid, state_mismatch) instead of the generic please_restart_the_process code. (#9788)
  • Fixed OAuth state validation failures to redirect to the per-flow errorCallbackURL instead of the default error page. (#9789)
  • Fixed OpenAPI schema generation to emit unique operationIds for endpoints that expose multiple HTTP methods. (#9721)
  • Fixed organization invitations silently routing users to the wrong team when team IDs contained a comma. (#9616)
  • Fixed deleteOrganization and removeMember to roll back on failure instead of leaving orphaned rows. (#9630)
  • Fixed stateless session cache refresh to preserve the real session expiry instead of resetting it. (#8817)
  • Fixed a session cookie leak that allowed session_token and session_data cookies to be captured and replayed to bypass 2FA when cookie caching is enabled. (#9639)
  • Fixed missing username validation on the admin createUser endpoint. (#9464)

For detailed changes, see CHANGELOG

@better-auth/oauth-provider

Bug Fixes

  • Fixed expired magic-link tokens and OAuth authorization codes to be reliably rejected, and corrected their error codes. (#9624)
  • Fixed the registration_endpoint to be hidden from .well-known metadata unless dynamic client registration is enabled. (#9448)
  • Fixed Basic Auth credential parsing to accept client_secret values containing colons. (#9601)
  • Fixed the consent update endpoint to return NOT_FOUND when the referenced client no longer exists. (#9600)
  • Fixed OAuth and OIDC metadata discovery for path-prefixed issuers. (#9668)

For detailed changes, see CHANGELOG

@better-auth/core

Features

  • Added toCamelCase, toSnakeCase, toPascalCase, and toKebabCase utilities to @better-auth/core/utils/string. (#9727) – @better-auth

Bug Fixes

  • Fixed Sign in with Apple to accept hashed nonces for native iOS sign-in. (#8870)
  • Fixed verifyAccessToken to return proper unauthorized errors for invalid token verification failures. (#9655)

For detailed changes, see CHANGELOG

@better-auth/sso

Bug Fixes

  • Fixed hook rejections in SSO OIDC and SAML callbacks to redirect to errorCallbackURL instead of returning a JSON error. (#9702)
  • Updated XML parser dependency to a patched release to resolve security alerts. (#9662)
  • Fixed SSO OIDC callback to URL-encode error values in redirect query strings. (#9722)

For detailed changes, see CHANGELOG

@better-auth/drizzle-adapter

Bug Fixes

  • Fixed the Drizzle adapter dropping OR clauses when mixed with AND conditions in where queries. (#9756)
  • Fixed MySQL insert-return handling with a robust cascading fallback strategy wrapped in a transaction. (#9665)

For detailed changes, see CHANGELOG

@better-auth/passkey

Bug Fixes

  • Fixed a crash when passkey transports is undefined. (#9746)
  • Fixed passkey challenges to be consumed atomically, preventing replay attacks, and improved error status codes for failed registrations and authentications. (#9622)

For detailed changes, see CHANGELOG

@better-auth/api-key

Bug Fixes

  • Fixed TypeScript TS4023 declaration emit errors by adding better-call as a peer dependency. (#9759)

For detailed changes, see CHANGELOG

@better-auth/electron

Bug Fixes

  • Fixed cookie serialization to percent-encode values containing special characters like `

For detailed changes, see CHANGELOG

@better-auth/kysely-adapter

Bug Fixes

  • Fixed SQLite introspectors (BunSqliteDialect, NodeSqliteDialect) incorrectly reporting tables as views. (#9615)

For detailed changes, see CHANGELOG

@better-auth/stripe

Bug Fixes

  • Improved URL normalization and Stripe search query escaping to handle edge cases correctly. (#9661)

For detailed changes, see CHANGELOG

Contributors

Thanks to everyone who contributed to this release:

@bytaesu, @chdanielmueller, @cyphercodes, @gustavovalverde, @jsj, @kgarg2468, @Paola3stefania, @ping-maxwell, @reslear

Full changelog: v1.6.11...v1.6.12

better-auth

Bug Fixes

  • Added an error code to the change-email-disabled response to help clients identify the rejection reason (#8948)
  • Fixed access-control role statement types so predefined organization roles expose only their configured permissions in TypeScript (#9507)
  • Fixed the anonymous plugin to correctly call onLinkAccount when email verification triggers auto sign-in (#9548)
  • Fixed device authorization to bind pending codes to the verifying session, preventing any authenticated user from approving or denying another user's device code (#9573)
  • Fixed a race condition in the magic-link plugin that allowed concurrent requests to mint multiple sessions from the same single-use token (#9572)
  • Fixed the oidc-provider and mcp plugins to require client_secret for confidential clients on refresh token grants and use constant-time secret comparison (#9576)
  • Hardened oidc-provider and mcp plugins to follow OAuth 2.1: removed "none" from advertised signing algorithms, defaulted plain PKCE off, and rejected incomplete PKCE parameters (#9575)
  • Fixed an invitation takeover vulnerability by enabling requireEmailVerificationOnInvitation by default and extending the verification gate to getInvitation and listUserInvitations (#9577)

For detailed changes, see CHANGELOG

@better-auth/oauth-provider

Bug Fixes

  • Fixed a race condition in the OAuth authorization-code grant that allowed concurrent token-exchange requests to mint multiple token sets from the same authorization code
  • Fixed a race condition in OAuth refresh-token rotation that allowed concurrent requests to fork refresh token families, and added a unique constraint on oauthRefreshToken.token
  • Fixed OAuth account linking to require a verified local email before linking an OAuth identity to a local account (#9578)

For detailed changes, see CHANGELOG

@better-auth/core

Bug Fixes

  • Fixed an invalid import list in the instrumentation module (#9582)
  • Widened advanced.ipAddress.ipv6Subnet to accept any valid IPv6 prefix length (0-128) instead of a narrow set of values (#9545)

For detailed changes, see CHANGELOG

@better-auth/scim

Bug Fixes

  • Fixed session cleanup to run when admin, anonymous, or SCIM operations delete a user (#9162)
  • Fixed generateSCIMToken to reject providerId values that collide with built-in account providers, preventing tokens from authenticating against unintended accounts (#9579)

For detailed changes, see CHANGELOG

@better-auth/sso

Bug Fixes

  • Fixed SSO provider registration to require an org admin or owner role, preventing any organization member from registering providers (#9220)
  • Fixed an SSRF vulnerability by validating user-supplied OIDC endpoint URLs against a public-routable host allowlist at provider registration and update (#9574)

For detailed changes, see CHANGELOG

auth

Features

  • Added an atomic claimOne adapter primitive for consuming database rows without race conditions (#9560)

Bug Fixes

  • Renamed the claimOne adapter primitive to consumeOne and added internalAdapter.consumeVerificationValue for atomically consuming verification rows (#9568)

For detailed changes, see CHANGELOG

@better-auth/api-key

Bug Fixes

  • Fixed API key rate-limited responses to return HTTP 429 instead of 401, so clients can distinguish throttling from authentication failures (#9505)

For detailed changes, see CHANGELOG

Contributors

Thanks to everyone who contributed to this release:

@dipan-ck, @GautamBytes, @gustavovalverde, @Kvizas, @ping-maxwell, @stewartjarod

Full changelog: v1.6.10...v1.6.11

better-auth

Bug Fixes

  • Exposed refreshUserSessions on the internal adapter (#7764)
  • Fixed organization invitation roles to accept dynamic access control roles (#9437)
  • Improved link accessibility (#9521)
  • Fixed incorrect email casing in one-tap, email-otp, and email-verification flows (#9369)
  • Fixed OpenAPI schema for POST /sign-in/social mis-declaring required fields (#9268)
  • Added a warning when the cookie plugin is placed last in the plugins array (#9484)
  • Fixed useSession not revalidating after admin impersonation starts or stops (#9402)
  • Fixed duplicate Set-Cookie headers being emitted on redirect responses from social sign-in and magic-link endpoints (#9497)
  • Fixed the bearer plugin writing duplicate cookie entries when merging the session token into request headers (#9387)
  • Fixed captcha plugin breaking the email-otp flow (#8339)
  • Fixed email enumeration protection not applying when emailAndPassword.autoSignIn is false (#8839)
  • Fixed a TypeError caused by non-ASCII characters in OAuth error descriptions on redirect (#9065)
  • Renamed internalAdapter.deleteAccount parameter from accountId to id to reflect that it queries by primary key (#9503)
  • Fixed OAuth callbacks accepting a missing provider account ID, which could link accounts under an undefined id (#9456)
  • Fixed cancelPendingInvitationsOnReInvite having no effect, where re-inviting the same email always returned USER_IS_ALREADY_INVITED_TO_THIS_ORGANIZATION (#9453)
  • Fixed a TS2742 type error caused by missing re-exports when using additionalFields in the organization plugin (#9349)
  • Fixed useActiveMemberRole retaining a previous user's role after sign-out in SPA flows (#9440)
  • Fixed setActiveTeam to only accept teams from the currently active organization (#9239)
  • Added authClient.siwe.getNonce() as a compatibility alias for the SIWE nonce endpoint (#9461)
  • Fixed callbackURL being ignored on signIn.username, so it now redirects correctly like signIn.email (#9475)

For detailed changes, see CHANGELOG

@better-auth/oauth-provider

Bug Fixes

  • Fixed sessionId typing in refresh token types to be optional, matching the schema (#9324)
  • Fixed stale prompt=login consent continuations not completing after a forced login
  • Exported OAuth provider helper types needed for portable downstream TypeScript declaration emit (#9406)
  • Fixed prompt=login not being honored after consent continuation, preventing session bypass (#9344)
  • Added database indexes to OAuth provider foreign-key fields in generated schemas (#9389)

For detailed changes, see CHANGELOG

@better-auth/stripe

Bug Fixes

  • Fixed onSubscriptionUpdate to receive the raw stripeSubscription object, and fixed onSubscriptionCancel to receive the post-update subscription row instead of a stale snapshot (#9354)
  • Fixed getCheckoutSessionParams overriding internally managed Stripe Checkout Session fields such as success_url, cancel_url, customer, and line_items (#9481)
  • Fixed onSubscriptionDeleted, onTrialEnd, and onTrialExpired receiving a stale pre-update subscription snapshot instead of the post-update row (#9356)
  • Fixed getCheckoutSessionParams overriding free trial and internal metadata, which could hide trial periods and create duplicate subscription rows on webhook (#9474)
  • Renamed internal subscription webhook variables for clarity (#9355)

For detailed changes, see CHANGELOG

@better-auth/api-key

Bug Fixes

  • Fixed api.verifyApiKey not validating the key's configId against the request body (#9393)

For detailed changes, see CHANGELOG

@better-auth/core

Bug Fixes

  • Fixed Cloudflare Workers instrumentation imports to use a no-op entry when OpenTelemetry is not installed (#9395)

For detailed changes, see CHANGELOG

@better-auth/passkey

Bug Fixes

  • Fixed passkey autofill authentication to return a handled cancellation instead of an unhandled error when it cannot start (#9429)

For detailed changes, see CHANGELOG

@better-auth/sso

Bug Fixes

  • Fixed /sso/saml2/sp/metadata throwing NOT_FOUND for providers configured via defaultSSO (#9398)

For detailed changes, see CHANGELOG

auth

Bug Fixes

  • Fixed auth init generating broken MySQL and PostgreSQL Kysely database configs (#9455)

For detailed changes, see CHANGELOG

Contributors

Thanks to everyone who contributed to this release:

@bytaesu, @Craga89, @cyphercodes, @dipan-ck, @dvanmali, @GautamBytes, @gustavovalverde, @IcanDivideBy0, @jaydeep-pipaliya, @mausic, @onmax, @ping-maxwell, @programming-with-ia, @zllovesuki

Full changelog: v1.6.9...v1.6.10

better-auth

Bug Fixes

  • Fixed instrumentation resolution in the adapter factory so edge and browser environments correctly use the pure variant (#9340)

For detailed changes, see CHANGELOG

Contributors

Thanks to everyone who contributed to this release:

@erquhart

Full changelog: v1.6.8...v1.6.9

better-auth

Bug Fixes

  • Fixed mapProfileToUser fallback for OAuth providers that may omit email from their profile response (#9331)
  • Fixed support for passing id through beforeCreateTeam and beforeCreateInvitation hooks (#9253)

For detailed changes, see CHANGELOG

@better-auth/oauth-provider

Bug Fixes

  • Fixed authorization flows that do not include a state parameter (#9328)

For detailed changes, see CHANGELOG

@better-auth/passkey

Bug Fixes

  • Fixed incompatibility with TypeScript's exactOptionalPropertyTypes compiler option (#9270)

For detailed changes, see CHANGELOG

Contributors

Thanks to everyone who contributed to this release:

@baptisteArno, @gustavovalverde, @ping-maxwell

Full changelog: v1.6.7...v1.6.8

better-auth

Features

  • Added support for an array of client IDs as the ID token audience in social providers (#9292)

Bug Fixes

  • Fixed response headers being lost when an APIError is thrown (#9211)
  • Fixed browser and edge runtime errors by serving a no-op ./instrumentation module in those environments (#9281)
  • Fixed a crash when parsing OAuth2 state with an undefined request body (#9293)
  • Fixed callbackOnVerification not being called when updatePhoneNumber is enabled (#4894)

For detailed changes, see CHANGELOG

@better-auth/oauth-provider

Bug Fixes

  • Fixed the userinfo endpoint to read the Authorization header from request context when using auth.api (#9244)

For detailed changes, see CHANGELOG

@better-auth/passkey

Bug Fixes

  • Fixed passkey authentication verification not returning the user (#5209)

For detailed changes, see CHANGELOG

Contributors

Thanks to everyone who contributed to this release:

@gustavovalverde, @Kinfe123, @ouwargui, @ramonclaudio, @stewartjarod, @TanishValesha

Full changelog: v1.6.6...v1.6.7

better-auth

Bug Fixes

  • Fixed preservation of the Partitioned attribute when forwarding Set-Cookie headers (#9235)
  • Fixed boolean coercion for the disableRefresh query parameter in custom session validation (#9214)
  • Fixed incorrect inference of team additional fields in the organization plugin (#9266)
  • Added support for removing a phone number via updateUser({ phoneNumber: null }) (#9219)

For detailed changes, see CHANGELOG

@better-auth/core

Features

  • Added mapConcurrent, a bounded-concurrency async utility, at @better-auth/core/utils/async (#9227) – @better-auth

Bug Fixes

  • Made @opentelemetry/api an optional peer dependency (#9111) – @opentelemetry

For detailed changes, see CHANGELOG

@better-auth/api-key

Bug Fixes

  • Improved performance by running secondary-storage API key lookups in parallel (#9187)

For detailed changes, see CHANGELOG

@better-auth/expo

Bug Fixes

  • Fixed session loading to read cached data from SecureStore on app startup, eliminating the login screen flash for returning users (#8953)

For detailed changes, see CHANGELOG

@better-auth/oauth-provider

Bug Fixes

  • Fixed several SSRF vulnerabilities by unifying host classification and closing loopback bypass vectors across packages (#9226)

For detailed changes, see CHANGELOG

@better-auth/sso

Bug Fixes

  • Fixed an ESM/CJS compatibility issue when loading samlify (#9262)

For detailed changes, see CHANGELOG

Contributors

Thanks to everyone who contributed to this release:

@bytaesu, @gustavovalverde, @jonathansamines, @ping-maxwell, @terijaki

Full changelog: v1.6.5...v1.6.6

better-auth

Bug Fixes

  • Clarified recommended production usage for the test utils plugin (#9119)
  • Fixed session not refreshing after /change-password and /revoke-other-sessions (#9087)

For detailed changes, see CHANGELOG

@better-auth/oauth-provider

Security

  • Fixed GHSA-xr8f-h2gw-9xh6, a high-severity authorization bypass in @better-auth/oauth-provider where unprivileged authenticated users could create OAuth clients when deployments relied on clientPrivileges to restrict client creation. – @better-auth
  • First patched stable version: @better-auth/oauth-provider@1.6.5. – @better-auth @1
  • Note: the published beta line (1.7.0-beta.0 and 1.7.0-beta.1) remains affected until a fixed beta release is published.

For detailed changes, see CHANGELOG

Contributors

Thanks to everyone who contributed to this release:

@GautamBytes, @ramonclaudio

Full changelog: v1.6.4...v1.6.5

better-auth

Bug Fixes

  • Fixed forceAllowId UUIDs set in database hooks being ignored on PostgreSQL adapters when advanced.database.generateId is set to "uuid" (#9068)
  • Reverted 2FA enforcement scope to credential sign-in paths only, so magic link, email OTP, OAuth, SSO, passkey, and other non-credential sign-in flows no longer trigger a 2FA challenge (#9205)

For detailed changes, see CHANGELOG

Contributors

Thanks to everyone who contributed to this release:

@GautamBytes, @gustavovalverde

Full changelog: v1.6.3...v1.6.4

better-auth

Features

  • Added support for Stripe SDK v21 and v22 (#9084)

Bug Fixes

  • Fixed incorrect operationId for the requestPasswordResetCallback endpoint in the OpenAPI spec (#9072)
  • Fixed dynamic baseURL resolution from request headers for direct auth.api calls (#9113)
  • Fixed isMounted race condition that caused excessive requests per second in the client (#9078)
  • Fixed nullable schema for the get-session endpoint in the OpenAPI 3.1 spec (#8389)
  • Fixed checkout and upgrade flows to omit quantity for metered prices (#8926)
  • Fixed 2FA enforcement to trigger on all sign-in paths, including magic-link, OAuth, passkey, email-OTP, and SIWE (#9122)
  • Fixed backup code updates to respect the configured storeBackupCodes storage strategy after verification (#7231)

For detailed changes, see CHANGELOG

@better-auth/oauth-provider

Features

  • Added customTokenResponseFields callback for injecting custom fields into token endpoint responses, and hardened authorization code validation (#9118)

Bug Fixes

  • Hardened dynamic baseURL resolution for direct auth.api calls and plugin metadata helpers (#9131)
  • Fixed unauthenticated dynamic client registration to silently override confidential auth methods to public, improving compatibility with MCP clients (#9123)

For detailed changes, see CHANGELOG

@better-auth/sso

Bug Fixes

  • Fixed multiple SAML response processing bugs, including ACS URL generation, encryption field handling, and provider config parsing (#9097)

For detailed changes, see CHANGELOG

@better-auth/stripe

Bug Fixes

  • Fixed prototype pollution vulnerability when merging user-supplied metadata in the Stripe plugin (#9164)

For detailed changes, see CHANGELOG

auth

Bug Fixes

  • Fixed tsconfig path alias resolution for extended configs and mid-path wildcards in the CLI (#9032)

For detailed changes, see CHANGELOG

Contributors

Thanks to everyone who contributed to this release:

@bytaesu, @Byte-Biscuit, @gustavovalverde, @Oluwatobi-Mustapha, @ping-maxwell, @ramonclaudio

Full changelog: v1.6.2...v1.6.3

better-auth

❗ Breaking Changes

  • Prevented unverified TOTP enrollment from blocking sign-in (#8711)

Migration: Schema migration required.

Add the verified column to the twoFactor table, then regenerate/apply your ORM migration.

  • Prisma: run npx auth@latest generate, then npx prisma migrate dev (or npx prisma db push) and npx prisma generate.
  • Drizzle: run npx auth@latest generate, then npx drizzle-kit generate and npx drizzle-kit migrate.

Existing rows do not need a backfill because the column defaults to true.

Features

  • Included enabled 2FA methods in sign-in redirect response (#8772)

Bug Fixes

  • Fixed OAuth state verification against cookie-stored nonce to prevent CSRF (#8949)
  • Fixed infinite router refresh loops in nextCookies() by replacing cookie probe with header-based RSC detection (#9059)
  • Fixed cross-provider account collision in link-social callback (#8983)
  • Included RelayState in signed SAML AuthnRequests (#9058)

For detailed changes, see CHANGELOG

@better-auth/oauth-provider

Bug Fixes

  • Fixed multi-valued query params collapsing through prompt redirects (#9060)
  • Rejected skip_consent at schema level in dynamic client registration (#8998)

For detailed changes, see CHANGELOG

@better-auth/sso

Bug Fixes

  • Fixed SAMLResponse decoding failures caused by line-wrapped base64 (#8968)

For detailed changes, see CHANGELOG

Contributors

Thanks to everyone who contributed to this release:

@aarmful, @cyphercodes, @dvanmali, @gustavovalverde, @jaydeep-pipaliya, @ping-maxwell

Full changelog: v1.6.1...v1.6.2

better-auth

Bug Fixes

  • Fixed endpoint instrumentation to always use the route template (#9023)
  • Returned INVALID_PASSWORD for all checkPassword failures (#8902)
  • Restored getSession accessibility in generic Auth<O> context (#9017)

For detailed changes, see CHANGELOG

Contributors

Thanks to everyone who contributed to this release:

@bytaesu, @jonathansamines, @ping-maxwell

Full changelog: v1.6.0...v1.6.1

Blog post: Better Auth 1.6

better-auth

❗ Breaking Changes

  • Aligned freshAge calculation with session creation time instead of update time (#8762)

Migration: session.freshAge now calculates from createdAt. Set session: { freshAge: 0 } to disable the check entirely.

Features

  • Added experimental OpenTelemetry instrumentation for endpoints, hooks, middleware, and database operations (#8027)
  • Added resendStrategy option to reuse existing OTP in email-otp plugin (#8560)
  • Added enable option for HaveIBeenPwned plugin (#8728)
  • Added request metadata to sendMagicLink callback (#8571)
  • Added dedicated secret option to OAuth proxy to reduce shared key exposure (#8699)
  • Added explicit organizationId parameter in team endpoints (#5062)
  • Added WeChat social provider (#5189)
  • Added twoFactorPage config option for custom 2FA page routing (#5329)

Bug Fixes

  • Deprecated oidc-provider plugin in favor of @better-auth/oauth-provider (#8985) – @better-auth
  • Fixed access control indexing type (#8155)
  • Added origin check middleware to password reset request (#8392)
  • Fixed account cookie comparison to use provider accountId instead of internal id (#8786)
  • Fixed session id generation when using secondary storage without database (#8927)
  • Fixed skipOriginCheck array handling (#8582)
  • Fixed misleading rate limit IP warning (#8617)
  • Passed user field through idToken sign-in body for Apple name support (#8417)
  • Preserved custom session fields on focus refresh (#8354)
  • Fixed double encoded cookie (#8133)
  • Prevented revoked sessions from being restored via database fallback (#8708)
  • Resolved duplicate operationId in admin plugin endpoints (#8570)
  • Rethrew phone sendOTP failures instead of silently swallowing them (#8842)
  • Set stateless cookieCache maxAge to match session.expiresIn (#8648)
  • Threw on duplicate email when autoSignIn: false without requireEmailVerification (#8521)
  • Fixed accountInfo endpoint to use accountId instead of internal id (#8346)
  • Restored deprecated createAdapter and type exports for backwards compatibility (#8461)
  • Fixed Response return for HTTP request contexts (#7521)
  • Fixed throw: true handling in client session refresh (#8610)
  • Preserved stale session data on network or server errors (#8437)
  • Fixed bundler re-export type resolution with direct imports (#8261)
  • Fixed Set-Cookie header splitting with lookahead heuristic (#8301)
  • Prioritized generateId: "uuid" over adapter customIdGenerator (#8679)
  • Fixed date string revival in safeJSONParse for pre-parsed objects (#8248)
  • Fixed postgres migration to use CREATE INDEX (#8538)
  • Triggered sessionSignal after requesting email change in email-otp (#8816)
  • Fixed generic-oauth to use discovery userinfo endpoint instead of hardcoded URLs (#8223)
  • Normalized missing resolver path in last-login-method plugin (#8589)
  • Returned additional fields in /magic-link/verify (#7223)
  • Fixed OAuth proxy to read callback params from body for form_post (#8895)
  • Fixed double-hashing of OAuth state when storeIdentifier is hashed (#8980)
  • Fixed redirect_uri validation for prompt=none in oidc-provider (#8398)
  • Opted into FedCM to suppress Google GSI deprecation warnings (#8720)
  • Filtered null organizations in listUserInvitations (#8694)
  • Fixed multi-role user handling in invite and member removal checks (#8442)
  • Enforced authorization on SCIM management endpoints and normalized passkey ownership checks (#8843)
  • Allowed passwordless users to manage 2FA (#7243)
  • Wired twoFactorTable option to schema modelName (#8443)
  • Prevented any from collapsing auth.$Infer and client inference types (#8981)
  • Fixed updateUser to not overwrite unrelated username fields (#7570)
  • Enforced username uniqueness in updateUser (#8731)
  • Used non-blocking scrypt for password hashing to avoid blocking the event loop (#8685)

For detailed changes, see CHANGELOG

@better-auth/sso

❗ Breaking Changes

  • Enabled InResponseTo validation by default for SP-initiated SAML flows (#8736)

Migration: Set sso({ saml: { enableInResponseToValidation: false } }) to restore the previous behavior.

Features

  • Added logging for OIDC callback code validation failures (#8693)

Bug Fixes

  • Patched transitive node-forge vulnerability via samlify pin (#8838)
  • Fixed bare domain handling in domain verification (#8369)
  • Preferred UserInfo endpoint over ID token and mapped sub claim correctly (#8276)
  • Fixed provisionUser inconsistency and added provisionUserOnEveryLogin option (#8818)
  • Skipped state cookie check for SAML ACS cross-site POST (#8735)
  • Fixed verification operations to use internalAdapter (#8353)
  • Fixed ESM compatibility with namespace import for samlify (#8697)

For detailed changes, see CHANGELOG

@better-auth/mongo-adapter

❗ Breaking Changes

  • Stored UUIDs as native BSON UUID type (#8681)

Migration: New documents use native BSON UUIDs. Existing string UUIDs continue to work. No data migration required.

For detailed changes, see CHANGELOG

@better-auth/oauth-provider

Features

  • Added pairwise subject identifiers (OIDC Core Section 8) (#8292)
  • Added public client prelogin endpoint (#8214)

Bug Fixes

  • Allowed localhost subdomains in isLocalhost function (#8286)
  • Fixed fetch redirect CORS after login (#8519)
  • Allowed customIdTokenClaims to override standard claims (#7865)
  • Enforced DB-backed sessions when secondary storage is enabled (#8894)
  • Fixed dist declaration type errors (#8701)
  • Fixed dynamic baseURL config handling in init (#8649)
  • Improved allowed paths for oauth_query in client plugin (#8320)
  • Allowed customIdTokenClaims to override acr and auth_time (#8633)
  • Normalized auth_time timestamps across adapter shapes (#8761)
  • Returned JSON redirects from post-login OAuth continuation to fix CORS-blocked 302s (#8815)
  • Fixed PAR scope loss, loopback redirect matching, and DCR skip_consent (#8632)
  • Added prompt=none support (#8554)

For detailed changes, see CHANGELOG

@better-auth/stripe

Features

  • Added customizable prorationBehavior per plan (#8525)

Bug Fixes

  • Improved organization customer search by adding customerType check (#8609)
  • Replaced {CHECKOUT_SESSION_ID} placeholder in success callbackURL (#8568)
  • Returned correct priceId for annual subscriptions in list (#8810)

For detailed changes, see CHANGELOG

@better-auth/drizzle-adapter

Features

  • Added case-insensitive query support (mode: "insensitive") (#8556)

Bug Fixes

  • Fixed Drizzle adapter failing date transformation (#8289)
  • Used IS NULL / IS NOT NULL for null value comparisons (#8660)

For detailed changes, see CHANGELOG

@better-auth/expo

Features

  • Exposed plugin version field on all built-in plugins (#8750)

Bug Fixes

  • Fixed shim require issue (#8253)
  • Fixed origin override handling across mutable and immutable requests (#8405)

For detailed changes, see CHANGELOG

@better-auth/prisma-adapter

Bug Fixes

  • Moved adapter packages to dependencies to fix missing module errors (#8401)
  • Used updateMany fallback for non-unique updates (#8524)
  • Used deleteMany when deleting by non-unique field (#8314)

For detailed changes, see CHANGELOG

auth

Features

  • Migrated MCP server URL to mcp.better-auth.com (#8747)

Bug Fixes

  • Fixed path alias resolution from extended tsconfig files (#8520)
  • Treated omitted required as true in Drizzle and Prisma generators (#8614)

For detailed changes, see CHANGELOG

@better-auth/electron

Bug Fixes

  • Fixed verification operations with secondary storage (#8247)
  • Handled safeStorage encryption failures gracefully (#8530)

For detailed changes, see CHANGELOG

@better-auth/passkey

Features

  • Added pre-auth registration and WebAuthn extensions support (#7154)

Bug Fixes

  • Fixed error message strings in passkey client (#8751)

For detailed changes, see CHANGELOG

@better-auth/test-utils

Features

  • Exported adapter test suites from @better-auth/test-utils/adapter (#8564) – @better-auth

Bug Fixes

  • Removed using keyword for runtime compatibility (#8756)

For detailed changes, see CHANGELOG

@better-auth/api-key

Bug Fixes

  • Fixed turbo caching, enforced lockfile integrity, and expanded pre-commit hooks (#8892)

For detailed changes, see CHANGELOG

@better-auth/core

Bug Fixes

  • Stopped marking redirect APIErrors as span errors in OpenTelemetry traces (#8850)

For detailed changes, see CHANGELOG

@better-auth/kysely-adapter

Bug Fixes

  • Removed deprecated numUpdatedOrDeletedRows from D1 dialect (#8798)

For detailed changes, see CHANGELOG

@better-auth/telemetry

Bug Fixes

  • Used conditional exports to replace dynamic import hacks (#8458)

For detailed changes, see CHANGELOG

Contributors

Thanks to everyone who contributed to this release:

@aarmful, @bytaesu, @dvanmali, @Eric-Song-Nop, @formatlos, @GautamBytes, @GoPro16, @gustavovalverde, @himself65, @jonathansamines, @jslno, @mrgrauel, @NathanColosimo, @okisdev, @olliethedev, @Oluwatobi-Mustapha, @OscarCornish, @ping-maxwell, @raihanbrillmark, @sicarius97, @Sigmabrogz, @wuzgood98, @xiaoyu2er, @YevheniiKotyrlo

Full changelog: v1.5.6...v1.6.0

   🚀 Features

  • Agent auth plugin – @Bekacru
  • core: Add experimental opentelemetry instrumentation – @jonathansamines @bytaesu
  • email-otp: Add resendStrategy option to reuse existing OTP – @bytaesu
  • magic-link: Add request metadata to sendMagicLink – @mrgrauel
  • mongo-adapter: Store UUIDs as native BSON UUID – @bytaesu
  • oauth-provider: Public client prelogin endpoint – @dvanmali
  • organization: Explicit organizationId in team endpoints – @xiaoyu2er @himself65
  • social-provider: Add wechat social provider – @Eric-Song-Nop @himself65
  • stripe: Allow customizable prorationBehavior per plan – @bytaesu
  • test-utils: Export adapter test suites from @better-auth/test-utils/adapter@bytaesu
  • two-factor: Add twoFactorPage in config – @wuzgood98

   🐞 Bug Fixes

  • Handle skipOriginCheck array – @jslno
  • Prevent revoked sessions from being restored via database fallback – @bytaesu
  • api:
    • Return Response for HTTP request contexts – @gustavovalverde
  • client:
    • Handle throw:true in session refresh – @bytaesu
  • core:
    • Prioritize generateId "uuid" over adapter customIdGenerator – @bytaesu
  • docs:
    • Improve AI chat security and cleanup – @himself65
    • Add missing Encore icon to sidebar icons – @himself65
  • electron:
    • Handle safeStorage encryption failures gracefully – @jslno
  • oauth-provider:
    • Support prompt=none – @dvanmali
    • Improve allowed paths for oauth_query for client plugin – @dvanmali
    • Fix dist declaration type errors – @gustavovalverde
  • organization:
    • Filter null organizations in listUserInvitations – @raihanbrillmark
  • sso:
    • Use namespace import for samlify to fix ESM compatibility – @himself65
  • stripe:
    • Replace {CHECKOUT_SESSION_ID} placeholder in success callbackURL – @bytaesu
    • Improve organization customer search by adding customerType check – @bytaesu
    View changes on GitHub

   🐞 Bug Fixes

  • cli: Warn when old @better-auth/cli is used with better-auth v1.5.x+ – @himself65
    View changes on GitHub

   🚀 Features

  • oauth-provider: Pairwise subject identifiers (OIDC Core §8) – @gustavovalverde @himself65

   🐞 Bug Fixes

  • Pass user field through idToken sign-in body for Apple name support – @bytaesu
  • Add missing SubpageItem properties for docs-sidebar compatibility – @bytaesu
  • Add icon prop to SubpageLink component – @bytaesu
  • Correct sign-in link to dash.better-auth.com – @bytaesu
  • Restore features.tsx and align import with canary – @bytaesu
  • Add suppressHydrationWarning to video elements – @bytaesu
  • Preserve custom session fields on focus refresh – @jslno
  • Throw on duplicate email when autoSignIn: false without requireEmailVerification@himself65
  • Add origin check middleware to password reset request – @jslno
  • adapters: Restore deprecated createAdapter and type exports for backcompat – @himself65
  • blog: Fix RSS feed link path, image path and blog date – @0-Sandy
  • cli: Resolve path aliases from extended tsconfig files – @himself65
  • client: Preserve stale session data on network or server errors – @bytaesu
  • db: Use CREATE INDEX for postgres migration – @himself65
  • oauth-provider: Avoid fetch redirect CORS after login – @GautamBytes
  • oidc-provider: Validate redirect_uri for prompt=none – @jslno
  • organization: Handle multi-role users in invite and member removal checks – @himself65
  • prisma-adapter: Fall back to updateMany for non-unique updates – @himself65
  • sso: Handle bare domains in domain verification – @himself65
  • telemetry: Use conditional exports to replace dynamic import hacks – @himself65
  • two-factor: Wire twoFactorTable option to schema modelName – @himself65
    View changes on GitHub

   🐞 Bug Fixes

  • Move adapter packages to dependencies to fix missing module errors – @himself65
  • expo: Handle origin override across mutable and immutable requests – @NathanColosimo @bytaesu
    View changes on GitHub

   🐞 Bug Fixes

  • account: Use accountId instead of id in accountInfo endpoint – @NathanColosimo @himself65
  • sso: Use internalAdapter for verification operations – @himself65
    View changes on GitHub

   🐞 Bug Fixes

  • Access control indexing type – @YevheniiKotyrlo @himself65
  • Prevent double encoded cookie – @Oluwatobi-Mustapha @himself65
  • cookies:
    • Use lookahead heuristic for splitting Set-Cookie headers – @bytaesu
  • oauth-provider:
    • Allow localhost subdomains in isLocalhost function – @sicarius97 @himself65
    • CustomIdTokenClaims should override standard claims – @gustavovalverde
  • prisma-adapter:
    • Use deleteMany when deleting by non-unique field – @himself65
  • sso:
    • Prefer UserInfo endpoint over ID token and map sub claim correctly – @himself65
    View changes on GitHub

   🐞 Bug Fixes

  • client: Use direct imports to fix bundler re-export type resolution – @himself65
  • core: Revive date strings in safeJSONParse for pre-parsed objects – @himself65
  • db: Support verification operations with secondary storage – @himself65
  • expo: Avoid shim require@himself65
  • generic-oauth: Use discovery userinfo endpoint instead of hardcoded URLs – @himself65
    View changes on GitHub