npm better-auth 1.6.17
v1.6.17

6 hours ago

better-auth

Features

  • Added an experimental oauthPopup plugin for popup-based OAuth sign-in, enabling sign-in inside cross-site iframes by completing the OAuth flow in a popup and passing the session token back via the bearer plugin (#9890)

Bug Fixes

  • Fixed getCookieCache to return null for an expired session instead of stale data, so middleware no longer treats an expired signed cookie as a live session.
  • Fixed a race condition where a delete-account confirmation link could delete the account more than once when its callback was opened concurrently.
  • Fixed a race condition where a one-time token could be redeemed for a session more than once when redeemed concurrently.
  • Fixed a race condition where a password reset token could change the password more than once when used from concurrent requests.
  • Fixed Reddit sign-in to assign a non-routable placeholder address (<id>@reddit.invalid) to users with no email, instead of one on the real reddit.com domain, preventing accidental mailbox matches. The address stays unverified, and mapProfileToUser can supply a real email.
  • Fixed Sign-In with Ethereum to prevent a nonce from being used to sign in more than once when submitted from concurrent requests.
  • Added internalAdapter.reserveVerificationValue for atomic single-use markers, ensuring exactly one concurrent caller succeeds and the rest see the marker as already taken, hardening replay protection across all verification flows. Database-backed storage is atomic; secondary-storage-only mode is best-effort.
  • Added the optional incrementOne adapter method and SecondaryStorage.increment for atomic counter updates with conditional row guards, enabling strict enforcement of rate limits and usage counters. Adapters without native support fall back to a transaction-based approach.
  • Fixed expired two-factor sign-in challenges from completing login, and prevented the same challenge from creating more than one session when verified concurrently.
  • Fixed captcha provider verification to time out after 10 seconds and fail closed, preventing a slow or unreachable provider from blocking requests indefinitely.
  • Fixed /delete-user/callback to reject account deletion when the session has been revoked server-side, instead of proceeding within the cookie-cache window. Deployments that keep sessions only in the cookie are unaffected.
  • Fixed concurrent requests from slipping past the configured rate limit, resolved unbounded memory growth in the in-memory rate-limit store, and made the database backend remove expired entries automatically. A custom rate-limit storage may implement a new optional consume method for strict enforcement.
  • Fixed team deletion to preserve pending invitations, which now drop the removed team and remain valid for their remaining teams or as organization-level invitations.
  • Downgraded expected auth validation failures from error logs to warnings.
  • Fixed expired MCP access tokens from being accepted, and restricted refresh token acceptance to authorizations that included the offline_access scope.
  • Fixed team member limits to be enforced on addMember and add-team-member paths, preventing teams from exceeding their maximumMembersPerTeam cap, and ensured a rejected addMember does not create the organization member (#10002)
  • Fixed generic OAuth sign-in for providers whose userinfo response lacks a sub or id field when mapProfileToUser derives the account id (#9987)
  • Fixed single-use credentials, counters, and replay markers to be handled atomically under concurrent requests (#9993)
  • Fixed stateless OAuth deployments to correctly read account info and tokens when different server instances handle sign-in and subsequent requests (#9979)
  • Fixed admin.setUserPassword to create a credential account for users who only have social or magic-link accounts, enabling direct password assignment without manually modifying the account table (#9482)
  • Fixed updateSession to accept custom session fields inferred from inferAdditionalFields (#9777)
  • Fixed duplicate /get-session requests triggered by focus and other browser events, stabilized client hook data references to reduce unnecessary re-renders, and resolved session state getting stuck loading after unmounting during an in-flight request (#8760)
  • Fixed the OpenAPI schema to mark model id fields as required (#9704)
  • Fixed updateMemberRole to reject unknown or malformed role values, validating them against configured static and dynamic roles (#9962)
  • Fixed a memory leak where the JWKS cache grew on every access token verification.
  • Fixed Google One Tap to require a configured client ID and reject ID tokens issued for a different application, preventing unauthorized sign-ins.
  • Fixed a race condition where polling for a device-authorization token could redeem the same approved device code more than once.
  • Fixed account cookie handling when switching users in the same browser, preserving the fresh cookie instead of expiring it from stale request state.
  • Refactored role.authorize control flow without changing existing authorization behavior (#9677)
  • Fixed a race condition where submitting the same email OTP from concurrent requests could sign in more than once or exceed the attempt limit.
  • Fixed a race condition where submitting the same phone-number OTP from concurrent requests could sign in more than once or exceed the attempt limit.
  • Fixed a race condition where submitting the same two-factor OTP from concurrent requests could sign in more than once or exceed the attempt limit.
  • Improved the Have I Been Pwned plugin to check submitted passwords on more endpoints by default, including email-OTP and phone-number reset-password routes and admin create-user and set-user-password routes.
  • Fixed multi-session set-active and revoke endpoints to only act on sessions the caller holds a signed cookie for, preventing unauthorized activation or revocation of other sessions.
  • Fixed the OIDC /oauth2/endsession endpoint to reject cross-site GET logout requests carrying only a session cookie, while leaving logout authenticated by a valid id_token_hint unaffected.
  • Fixed WeChat sign-in to succeed without an email address by assigning a stable placeholder, matching the behavior expected from the default configuration.

For detailed changes, see CHANGELOG

@better-auth/api-key

Bug Fixes

  • Fixed API key updates to fail when the caller's session has been revoked server-side, instead of succeeding within the cookie-cache window (#9991)
  • Prevented server-only endpoints from being accidentally exposed over HTTP (#9835)
  • Fixed concurrent API key verification from driving the remaining-uses count below zero or exceeding the rate limit. Secondary-storage-only deployments remain best-effort for these counters.

For detailed changes, see CHANGELOG

@better-auth/sso

Bug Fixes

  • Fixed SAML replay protection to hold under concurrent requests, preventing a SAML assertion submitted twice simultaneously from being accepted more than once.
  • Fixed SSO domain verification to allow organization admins and owners to verify domains for providers their organization owns, not just the member who originally registered the provider.
  • Fixed trustEmailVerified to no longer treat the string "false" as a verified email, accepting only a boolean true or the string "true" as confirmation.

For detailed changes, see CHANGELOG

auth

Bug Fixes

  • Fixed the CLI to resolve SvelteKit ($app/*, $env/*), Vite asset imports (?raw, ?url), and Cloudflare Workers (cloudflare:workers) virtual-module imports when loading the auth config (#9834)
  • Fixed the CLI to skip Unsupported() fields when regenerating the Prisma schema (#10011)
  • Fixed the CLI to update existing Prisma field types when regenerating the schema, such as correctly emitting BigInt or Int when bigint configuration changes (#9729)

For detailed changes, see CHANGELOG

@better-auth/expo

Bug Fixes

  • Hardened request trust validation for the Expo authorization proxy, including rejecting redirect and callback targets not in trustedOrigins (#9990)
  • Fixed Expo social account linking to include the stored session cookie when using an ID token with linkSocial (#9953)

For detailed changes, see CHANGELOG

@better-auth/memory-adapter

Bug Fixes

  • Fixed the memory adapter to not discard writes from concurrent operations on a failed transaction, made update and delete with an empty filter a no-op instead of affecting all rows, and made updateMany return the number of affected rows.
  • Fixed counter updates on the memory, Kysely, Drizzle, Prisma, and MongoDB adapters to be atomic by default, ensuring correct rate limiting and API-key usage limit enforcement.

For detailed changes, see CHANGELOG

@better-auth/scim

Bug Fixes

  • Fixed organization-scoped SCIM deletes to remove members through the organization adapter, ensuring team memberships and member-removal hooks are applied correctly.
  • Fixed SCIM bearer token comparison to use constant-time evaluation, closing a timing side channel that could help an attacker recover a valid token.

For detailed changes, see CHANGELOG

@better-auth/core

Bug Fixes

  • Fixed provider identity validation for Google One Tap, Microsoft Entra ID, SSO, WeChat, and Reddit sign-in to enforce tenant restrictions and reject tokens issued for other applications (#10003)

For detailed changes, see CHANGELOG

@better-auth/drizzle-adapter

Bug Fixes

  • Fixed updateMany to return the number of rows it affected, as the adapter contract specifies.

For detailed changes, see CHANGELOG

@better-auth/electron

Bug Fixes

  • Fixed a race condition where an Electron authorization code could be exchanged for a session more than once when the exchange was attempted concurrently.

For detailed changes, see CHANGELOG

@better-auth/kysely-adapter

Bug Fixes

  • Fixed SQLite mutations through the Bun and Node Kysely drivers to correctly report affected row counts and inserted row IDs, fixed multiple query parameter binding in the Bun driver, and made consumeOne work on SQL Server.

For detailed changes, see CHANGELOG

@better-auth/oauth-provider

Bug Fixes

  • Fixed token introspection and revocation to cache signing keys per auth instance instead of fetching them from the database on every request.

For detailed changes, see CHANGELOG

@better-auth/passkey

Bug Fixes

  • Fixed passkey challenge validation to reject registration challenges used for authentication (and vice versa), and to fail when the target user cannot be resolved.

For detailed changes, see CHANGELOG

@better-auth/prisma-adapter

Bug Fixes

  • Fixed the Prisma adapter to surface delete errors instead of silently reporting success when a deletion fails for any reason other than the record being absent.

For detailed changes, see CHANGELOG

@better-auth/redis-storage

Bug Fixes

  • Fixed Redis-backed rate-limit windows to set expiry once when the window opens instead of extending it with continued traffic, and added an atomic increment method to Redis secondary storage.

For detailed changes, see CHANGELOG

@better-auth/stripe

Bug Fixes

  • Fixed several Stripe subscription issues: reused existing customers by email only when verified, synced subscription status from the checkout session on success, scoped cancellation and restoration to the targeted subscription, validated returnUrl against trustedOrigins, and checked all subscriptions on organization deletion (#9971)

For detailed changes, see CHANGELOG

Contributors

Thanks to everyone who contributed to this release:

@arnnvv, @Bekacru, @bytaesu, @GautamBytes, @gustavovalverde, @SferaDev

Full changelog: v1.6.16...v1.6.17

Don't miss a new better-auth release

NewReleases is sending notifications on new releases.