Every release shipped to Better Auth, straight from GitHub.
Every release shipped to Better Auth, straight from GitHub.
better-authjose, nanostores, noble crypto packages, SimpleWebAuthn) to their latest compatible releases, with no changes required to existing projects.For detailed changes, see CHANGELOG
@better-auth/scimactive and the primary sub-attribute of emails, phoneNumbers, addresses, roles, and entitlements at the HTTP ingress, improving Microsoft Entra interoperability.managedConnections to allow trusted server code to create runtime tenant connections and issue, rotate, and revoke bearer credentials through server-only auth.api methods, without a code-defined connection or an application-owned verifier.For detailed changes, see CHANGELOG
@better-auth/ssowantAssertionsSigned now correctly controls whether the SP requires signed assertions, matching real-world IdP signing behavior.For detailed changes, see CHANGELOG
@better-auth/cimds-maxage over max-age and Expires, honors s-maxage=0, conditionally revalidates with ETag or Last-Modified, and treats invalid or duplicate freshness directives as immediately stale. Concurrent refreshes now converge on a single client-resource link instead of failing on a unique constraint.For detailed changes, see CHANGELOG
@better-auth/kysely-adapternode:sqlite, bun:sqlite, mysql2, pg) passed directly as database, matching the behavior of the explicit { db }/{ dialect } config shapes. Plugins requiring native transactions (such as @better-auth/scim) now work correctly when using the quickstart database: new Database(...) form.For detailed changes, see CHANGELOG
@better-auth/oauth-provider403 with an RFC 6750 insufficient_scope WWW-Authenticate challenge naming every missing scope, allowing clients to request all needed scopes in a single authorization request.For detailed changes, see CHANGELOG
authFor detailed changes, see CHANGELOG
Thanks to everyone who contributed to this release:
Full changelog: v1.7.0...v1.7.1
Blog post: Better Auth 1.7
better-authexperimental into the stable advanced.database.joins option (#10359)
Migration: Replace
experimental: { joins: true }withadvanced: { database: { joins: true } }. Drizzle and Prisma users should regenerate their schema (npx auth@latest generate) so it includes the required relations.
(issuer, accountId) (#10403)
Migration: Accounts now require
Account.issuer. Read provider identity fromaccountInfo.account.accountId, dropmapping.idfrom SSO configs, and give themicrosoftEntraIdhelper a concrete tenant GUID. Apply the account-identity backfill in the 1.7 upgrade guide before deploying.
Migration: Replace partial paths such as
/sign-inwith explicit wildcards like/sign-in/*or/sign-in/**.
@better-auth/mcp package built on the OAuth provider (#9992)
Migration: Install
@better-auth/mcpand@better-auth/cimd, add the now-requiredjwt()plugin, and move options nested underoidcConfigto flatmcp({ ... })options. RenamewithMcpAuthtorequireMcpAuthandmcpHandlertocreateMcpProtectedRequestHandler. Regenerate the schema (npx auth migrate):oauthApplicationbecomesoauthClient, plus newoauthRefreshTokenandoauthClientAssertiontables.
Migration: Introspecting an access token whose session has ended now returns
{ active: false }, and/oauth2/userinforejects it. Clients opt into notifications by registeringbackchannel_logout_uri. Run the schema migration for the newoauthClientandoauthAccessTokencolumns.
Migration:
validAudiencesis removed: move each resource identifier intoresourcesand link restricted clients throughoauthClientResource.@better-auth/mcpnow requires an explicitresource. Runnpx @better-auth/cli generateand apply the migration before deploying.
Migration: SCIM configuration, client APIs, database schema, and the Group model are all replaced, and provisioning state cannot migrate in place. Follow the SCIM cutover in the 1.7 upgrade guide, including a full directory reprovision, before resuming traffic.
enableTwoFactor response (#9057)
Migration:
enableTwoFactornow returns amethodfield ("otp"or"totp"); narrow on it before readingtotpURIandbackupCodes. Passmethod: "otp"for OTP enrollment, which requiresotpOptions.sendOTP.
Host by default when using a dynamic baseURL (#9134)
Migration: If your proxy exposes the public hostname only through
x-forwarded-host, setadvanced.trustedProxyHeaders: true. Deployments where the proxy rewritesHost(nginx default, Vercel, Cloudflare, Netlify) are unaffected.
deviceCode and userCode columns (#10059)
Migration: Resolve duplicate code values before applying the migration. MySQL and SQL Server installations must also convert both columns to bounded strings and clean up values longer than 191 characters.
Migration: Upgrade the
@better-auth/electronclient and server together and add your app's scheme totrustedOrigins. Thecode_challenge_methodparameter anddisableOriginOverrideoption are removed, and host-bearing custom-scheme entries now match that host exactly.
oid claim (#10204)
Migration: Migrate existing Microsoft account rows created from
subbefore upgrading. Tokens without a validoidare rejected.
Migration: Configure
oneTap({ clientId })orsocialProviders.google.clientId.
oidcProvider plugin (#10031)
Migration: Move OIDC authorization-server integrations to
@better-auth/oauth-provider.
Migration: Replace
signIn.oauth2({ providerId })withsignIn.social({ provider }),oauth2.link()withlinkSocial(), and dropgenericOAuthClient(). Callbacks move to/api/auth/callback/:id,pkcenow defaults totrue, andissuerandrequireIssuerValidationare removed in favor of OIDC discovery.
oauthDeviceAuthorization() (#10746)
Migration: The OAuth integration replaces the optional
resourcecolumn withoauthClientIdandresources, so regenerate and apply the schema. Let pending device codes expire before upgrading from an earlier 1.7 prerelease.
id_tokens with a single shared verifier (#9828)
Migration: Custom
UpstreamProviderimplementations replace the removedverifyIdTokenmethod with anidTokenconfig carrying a JWKS source, issuer, and audience. PayPal clientid_tokensign-in now returnsID_TOKEN_NOT_SUPPORTED; its redirect flow is unchanged.
clientAssertion support to the Microsoft Entra ID social provider (#9898)Auth instance directly fetchable (#9431)requireEmailVerification for social sign-in (#9929)user.validateUserInfo gate for rejecting an identity before a user is created or linked (#9864)hydrateSession so useSession returns server-fetched data on the first render (#8733)allowIdpInitiated support for IdP-initiated flows through a secure server-side bounce (#9301)signOut() can also sign users out of the OpenID provider (#9368)refreshTokenParams for forwarding extra parameters on generic OAuth token refresh (#9948)id_tokens against the provider JWKS and enabled id_token sign-in for generic OAuth (#9966)at_hash claim to ID tokens issued alongside an access token, per OIDC Core §3.1.3.6 (#9079)private_key_jwt client authentication for token endpoint requests (RFC 7523) (#8836)Cache-Control: no-store on every OAuth response that carries credentials (#10065)additionalParams and loginHint across signIn.social, linkSocial, and signIn.sso (#9305)userId and organizationId to the listUserTeams API (#8977)organization.getOrganization() for metadata-only fetches (#10397)consumePhoneNumberOTP API for custom phone OTP flows (#9766)displayUsername field (#10330)drizzle-kit peer dependency range (#10299)auth migrate to add required columns with static defaults and nullable unique columns to existing tables (#10293)nonce to the authorization request in the generic OAuth redirect flow (#10095)redirect_uri from the per-request base URL in multi-host deployments (#10127)account.scope values across re-authentication and token refresh (#10128)overrideUserInfo returns null (#10124)secondaryStorage (#9969)createAuthClient (#10505)For detailed changes, see CHANGELOG
@better-auth/oauth-provider@better-auth/mcp package built on the OAuth provider (#9992)
Migration: Install
@better-auth/mcpand@better-auth/cimd, add the now-requiredjwt()plugin, and move options nested underoidcConfigto flatmcp({ ... })options. RenamewithMcpAuthtorequireMcpAuthandmcpHandlertocreateMcpProtectedRequestHandler. Regenerate the schema (npx auth migrate):oauthApplicationbecomesoauthClient, plus newoauthRefreshTokenandoauthClientAssertiontables.
Migration: Introspecting an access token whose session has ended now returns
{ active: false }, and/oauth2/userinforejects it. Clients opt into notifications by registeringbackchannel_logout_uri. Run the schema migration for the newoauthClientandoauthAccessTokencolumns.
Migration: Add
applicationTypeand nullableclientDiscoveryIdcolumns, deduplicate existing(clientId, resourceId)links before the new compound unique index, then drop the legacytypeandpubliccolumns. ReplaceclientCredentialGrantDefaultScopeswith per-clientclientCredentialsScopes, backfilling every client to[]and reassigning approved machine scopes after an audit.mcp()no longer enables unauthenticated DCR: compose it withcimd()or enable both DCR flags explicitly.
max_age authorization request parameter (#9936)
Migration: Users who authenticated longer ago than the requested
max_ageare now sent back to log in, and the ID token'sauth_timereflects the fresh login. Flows that relied onmax_agebeing ignored will prompt again.
Migration:
customIdTokenClaims, extension claims, and per-issuanceidTokenClaimscan no longer set protocol claims such as issuer, subject, audience,nonce,auth_time,acr,amr, orazp; use namespaced custom claims instead. ID tokens now carryacr: "0"and discovery advertises only"0".
Migration:
validAudiencesis removed: move each resource identifier intoresourcesand link restricted clients throughoauthClientResource.@better-auth/mcpnow requires an explicitresource. Runnpx @better-auth/cli generateand apply the migration before deploying.
Migration: Remove
grantTypefromprovider.authenticateClient(...), and return{ clientId, confirmation? }from a customOAuthClientAuthenticationStrategy.authenticateinstead of a client record.
Migration: Token and refresh requests may only narrow the authorization's
resource; a broader request returnsinvalid_target.customAccessTokenClaimsnow receives aresourcesarray in place of theresourcestring. Run the schema migration to add the new resource columns.
Migration: Authorization errors now redirect to a registered client's trusted redirect URI with
stateandissinstead of rendering the server error page, and confidential clients must use their registeredtoken_endpoint_auth_method.
Migration: Replace
signIn.oauth2({ providerId })withsignIn.social({ provider }),oauth2.link()withlinkSocial(), and dropgenericOAuthClient(). Callbacks move to/api/auth/callback/:id,pkcenow defaults totrue, andissuerandrequireIssuerValidationare removed in favor of OIDC discovery.
oauthDeviceAuthorization() (#10746)
Migration: The OAuth integration replaces the optional
resourcecolumn withoauthClientIdandresources, so regenerate and apply the schema. Let pending device codes expire before upgrading from an earlier 1.7 prerelease.
@better-auth/cimd Client ID Metadata Document plugin (#9159)at_hash claim to ID tokens issued alongside an access token, per OIDC Core §3.1.3.6 (#9079)sessionId to id_token claim contributors (#10113)silenceWarnings option and the well-known endpoint warnings it suppressed (#10703)private_key_jwt client authentication for token endpoint requests (RFC 7523) (#8836)Cache-Control: no-store on every OAuth response that carries credentials (#10065)aud of private_key_jwt client assertions (#10811)offline_access without PKCE (#10153)401 invalid_token challenge from /oauth2/userinfo for invalid tokens (#10068)POST support and confirmation pages (#10812)acr claim requests per OIDC Core (#10790)profile and email scope claims on the UserInfo response instead of ID tokens (#10152)private_key_jwt jti single-use atomic across processes (#9964)redirect_uri conditional at the token endpoint, required only when the authorization included one (#10159)response_type to the verified client redirect URI (#10149)invalid_grant and revoked tokens issued from that code (#10150)unsupported_token_type when revoking a JWT access token (#9970)openid scope for authorization requests that use the claims parameter (#10791)invalid_grant when a client presents a refresh token issued to another client (#10154)403 with an RFC 6750 insufficient_scope challenge naming every one of them, so clients can request them in a single authorization redirect.For detailed changes, see CHANGELOG
@better-auth/coreexperimental into the stable advanced.database.joins option (#10359)
Migration: Replace
experimental: { joins: true }withadvanced: { database: { joins: true } }. Drizzle and Prisma users should regenerate their schema (npx auth@latest generate) so it includes the required relations.
(issuer, accountId) (#10403)
Migration: Accounts now require
Account.issuer. Read provider identity fromaccountInfo.account.accountId, dropmapping.idfrom SSO configs, and give themicrosoftEntraIdhelper a concrete tenant GUID. Apply the account-identity backfill in the 1.7 upgrade guide before deploying.
Migration: SCIM configuration, client APIs, database schema, and the Group model are all replaced, and provisioning state cannot migrate in place. Follow the SCIM cutover in the 1.7 upgrade guide, including a full directory reprovision, before resuming traffic.
oid claim (#10204)
Migration: Migrate existing Microsoft account rows created from
subbefore upgrading. Tokens without a validoidare rejected.
id_tokens with a single shared verifier (#9828)
Migration: Custom
UpstreamProviderimplementations replace the removedverifyIdTokenmethod with anidTokenconfig carrying a JWKS source, issuer, and audience. PayPal clientid_tokensign-in now returnsID_TOKEN_NOT_SUPPORTED; its redirect flow is unchanged.
clientAssertion support to the Microsoft Entra ID social provider (#9898)requireEmailVerification for social sign-in (#9929)user.validateUserInfo gate for rejecting an identity before a user is created or linked (#9864)allowIdpInitiated support for IdP-initiated flows through a secure server-side bounce (#9301)signOut() can also sign users out of the OpenID provider (#9368)refreshTokenParams for forwarding extra parameters on generic OAuth token refresh (#9948)includeGrantedScopes option to the Google provider (#10129)private_key_jwt client authentication for token endpoint requests (RFC 7523) (#8836)Cache-Control: no-store on every OAuth response that carries credentials (#10065)additionalParams and loginHint across signIn.social, linkSocial, and signIn.sso (#9305)client_id SSRF checks through the shared host classifier, which now rejects IPv4-compatible IPv6, the 6to4 relay prefix, and site-local addresses (#10126)redirect_uri from the per-request base URL in multi-host deployments (#10127)account.scope values across re-authentication and token refresh (#10128)createAuthClient (#10505)For detailed changes, see CHANGELOG
@better-auth/sso(issuer, accountId) (#10403)
Migration: Accounts now require
Account.issuer. SSO subjects are protocol-defined (subfor OIDC, signedNameIDfor SAML) andmapping.idis removed; a manual SAML config without metadata XML must setidpMetadata.entityID. Apply the account-identity backfill in the 1.7 upgrade guide before deploying.
Migration:
getSSOProvider,listSSOProviders, andupdateSSOProvidernow always returnsamlConfig.certificateas an array, so drop anyArray.isArraybranching. Registration rejects SAML configs with no signing-cert source withCERT_SOURCE_MISSING.
validateUserInfo source contract so it cannot be bypassed or spoofed (#9940)
Migration:
createUsernow fails closed whenvalidateUserInfois configured but no endpoint context or provisioning source is available. Read SSO metadata fromsource.ssoinstead ofsource.oauth, and handle thesource.methodvaluessso-oidcandsso-saml.
InResponseTo, audience restriction, and SessionIndex (#9055)
Migration:
allowIdpInitiatednow defaults tofalse. Setsaml.allowIdpInitiated: trueto keep accepting unsolicited SAML responses.
spMetadata optional, and fixed Single Logout (#9117)
Migration: Point your IdP's ACS URL at
/sso/saml2/sp/acs/:providerId;/sso/saml2/callback/:providerIdis removed.callbackUrlis now the post-auth redirect only, and the unuseddecryptionPvk,additionalParams,idpMetadata.entityURL, andidpMetadata.redirectURLfields are gone.
user.validateUserInfo gate for rejecting an identity before a user is created or linked (#9864)allowIdpInitiated support for IdP-initiated flows through a secure server-side bounce (#9301)private_key_jwt client authentication for token endpoint requests (RFC 7523) (#8836)additionalParams and loginHint across signIn.social, linkSocial, and signIn.sso (#9305)resolveUser to SAML sign-ins and hardened the provider lifecycle (#10621)additionalFields support on ssoProvider (#9445)wantAssertionsSigned now controls whether signed assertions are required rather than signed response messages, matching how IdPs sign SAML responses in practice.For detailed changes, see CHANGELOG
@better-auth/scimMigration: SCIM configuration, client APIs, database schema, and the Group model are all replaced, and provisioning state cannot migrate in place. Follow the SCIM cutover in the 1.7 upgrade guide, including a full directory reprovision, before resuming traffic.
Migration: Define connections statically, resolve them with
authentication.verifyBearerToken, or use the optionalmanagedConnectionscatalog, and connect SCIM resources to users and roles through identity and projection callbacks. Legacy SCIM state is not migrated: back it up, issue new credentials, and fully reprovision Users and Groups.
Migration: The legacy connection management endpoints and
providerOwnershipare gone, so authorize SCIM administration in your own application. LegacyscimProviderrows and credentials are not migrated: follow the 1.7 SCIM upgrade guide, issue new credentials, and reprovision Users and Groups.
user.validateUserInfo gate for rejecting an identity before a user is created or linked (#9864)acquireActiveSCIMUserLink for transaction-safe authentication of provisioned users (#10474)active and the primary sub-attribute of emails, phoneNumbers, addresses, roles, and entitlements at the HTTP ingress, for Microsoft Entra interoperability.managedConnections so trusted server code can create runtime tenant connections and issue, rotate, and revoke their bearer credentials through server-only auth.api methods, without a code-defined connection or an application-owned verifier.For detailed changes, see CHANGELOG
@better-auth/mcp ✨@better-auth/mcp package built on the OAuth provider (#9992)
Migration: Install
@better-auth/mcpand@better-auth/cimd, add the now-requiredjwt()plugin, and move options nested underoidcConfigto flatmcp({ ... })options. RenamewithMcpAuthtorequireMcpAuthandmcpHandlertocreateMcpProtectedRequestHandler. Regenerate the schema (npx auth migrate):oauthApplicationbecomesoauthClient, plus newoauthRefreshTokenandoauthClientAssertiontables.
Migration: Add
applicationTypeand nullableclientDiscoveryIdcolumns, deduplicate existing(clientId, resourceId)links before the new compound unique index, then drop the legacytypeandpubliccolumns. ReplaceclientCredentialGrantDefaultScopeswith per-clientclientCredentialsScopes, backfilling every client to[]and reassigning approved machine scopes after an audit.mcp()no longer enables unauthenticated DCR: compose it withcimd()or enable both DCR flags explicitly.
Migration:
mcp()now requires an explicitresourceidentifier, for exampleresource: "https://api.example.com/mcp".validAudiencesis removed: move each resource identifier intoresources. Runnpx @better-auth/cli generateand apply the migration before deploying.
For detailed changes, see CHANGELOG
@better-auth/electronMigration: Upgrade the
@better-auth/electronclient and server together and add your app's scheme totrustedOrigins. Thecode_challenge_methodparameter anddisableOriginOverrideoption are removed, and host-bearing custom-scheme entries now match that host exactly.
Migration: Replace
signIn.oauth2({ providerId })withsignIn.social({ provider }),oauth2.link()withlinkSocial(), and dropgenericOAuthClient(). Callbacks move to/api/auth/callback/:id,pkcenow defaults totrue, andissuerandrequireIssuerValidationare removed in favor of OIDC discovery.
createAuthClient (#10505)For detailed changes, see CHANGELOG
@better-auth/expoMigration:
getCookie()now returns a promise, and custom storage implementations must provide both synchronous and asynchronous SecureStore methods.storageAdapter.setItem()stays synchronous, so usesetItemAsync()when the write must be awaited.
Migration: Replace
signIn.oauth2({ providerId })withsignIn.social({ provider }),oauth2.link()withlinkSocial(), and dropgenericOAuthClient(). Callbacks move to/api/auth/callback/:id,pkcenow defaults totrue, andissuerandrequireIssuerValidationare removed in favor of OIDC discovery.
createAuthClient (#10505)For detailed changes, see CHANGELOG
@better-auth/stripeevent parameter of onSubscriptionCancel required (#9531)
Migration: Declare
eventas a required parameter in your callback and remove anyundefinedguards around it.
onSubscriptionCancel event parameter (#9359)
Migration:
eventis always supplied, so dropundefinedhandling from the callback.
For detailed changes, see CHANGELOG
authgrantedScopes string array (#9825)
Migration:
grantedScopesreplaces the comma-joinedaccount.scopestring with no read-time fallback, so backfill it from the existing values. The client provider contract is renamed fromOAuthProvidertoUpstreamProvider.
create-admin command for creating an initial admin user (#9547)Account.accountId alongside the required issuer (#10668)pgSchema binding so drizzle-kit can emit CREATE SCHEMA for custom PostgreSQL namespaces (#10770)resolveModule, adding support for the export default { auth } shape (#9477)account.scope storage (#10123)For detailed changes, see CHANGELOG
@better-auth/drizzle-adapterexperimental into the stable advanced.database.joins option (#10359)
Migration: Replace
experimental: { joins: true }withadvanced: { database: { joins: true } }, and regenerate the schema (npx auth@latest generate) so it includes the required relations.
relations-v2 entry point for projects using Drizzle Relations v2 (#9489)schemaName option that generates the Drizzle schema inside a pgSchema namespace (#7169)pgSchema binding so drizzle-kit can emit CREATE SCHEMA for custom PostgreSQL namespaces (#10770)For detailed changes, see CHANGELOG
@better-auth/cimd ✨Migration: Add
applicationTypeand nullableclientDiscoveryIdcolumns, deduplicate existing(clientId, resourceId)links before the new compound unique index, then drop the legacytypeandpubliccolumns. Client ID Metadata Documents preserve an omittedapplication_typeasnulland cannot assignclientCredentialsScopes. Composemcp()withcimd()for metadata-document clients.
@better-auth/cimd Client ID Metadata Document plugin (#9159)s-maxage over max-age and Expires, honors s-maxage=0, revalidates conditionally with ETag or Last-Modified, and treats invalid or duplicate freshness directives as immediately stale. Concurrent refreshes converge on one client-resource link instead of failing on its unique constraint.For detailed changes, see CHANGELOG
@better-auth/api-keyMigration: Custom adapters must implement native
consumeOneandincrementOne, secondary storage needs atomic consume and increment operations, and custom rate-limit storage makes oneconsumedecision per request. The read-then-delete and read-then-update fallbacks are removed.
For detailed changes, see CHANGELOG
@better-auth/kysely-adapternode:sqlite, bun:sqlite, mysql2, pg) passed directly as database now get native adapter transactions automatically, matching the behavior of the explicit { db } and { dialect } config shapes. This unblocks plugins that require native transactions (such as @better-auth/scim) when the database is provided in the quickstart database: new Database(...) shape.For detailed changes, see CHANGELOG
@better-auth/i18nFor detailed changes, see CHANGELOG
@better-auth/mongo-adapterFor detailed changes, see CHANGELOG
@better-auth/passkeycreateSession setting that signs the user in on successful passkey registration (#9873)For detailed changes, see CHANGELOG
Thanks to everyone who contributed to this release:
Full changelog: v1.6.30...v1.7.0
better-authFor detailed changes, see CHANGELOG
@better-auth/sso409 with SSO_PROVIDER_CHANGED if the provider changes during DNS resolution so callers can reload and retry.For detailed changes, see CHANGELOG
Thanks to everyone who contributed to this release:
Full changelog: v1.6.29...v1.6.30
better-authdeleteSessions performance by running deletes in parallel instead of sequentially (#10805)For detailed changes, see CHANGELOG
@better-auth/sso409 with SSO_PROVIDER_CHANGED if the provider changes during DNS verification so callers can reload and retry.For detailed changes, see CHANGELOG
Thanks to everyone who contributed to this release:
Full changelog: v1.6.28...v1.6.29
better-authFor detailed changes, see the CHANGELOG.
@better-auth/electronFor detailed changes, see the CHANGELOG.
@better-auth/expoFor detailed changes, see the CHANGELOG.
Thanks to everyone who contributed to this release:
Full changelog: v1.6.27...v1.6.28
better-authFor detailed changes, see CHANGELOG
@better-auth/scimbetter-call (#10657)For detailed changes, see CHANGELOG
authFor detailed changes, see CHANGELOG
Thanks to everyone who contributed to this release:
Full changelog: v1.6.26...v1.6.27
better-authfindSessions to skip invalid secondary-storage session entries without discarding other valid sessions (#10580)jwtClient() collapsing createAuthClient type inference when combined with other client plugins (#10513)oAuthProxy to preserve Apple user data from form_post callbacks (#10599)oneTapClient() collapsing createAuthClient type inference when combined with other client plugins (#10635)nextCookies performance in instrumented Next.js applications by reusing the next/headers import promise (#10467)For detailed changes, see CHANGELOG
@better-auth/coreplaceholder.invalid domain (#10576)For detailed changes, see CHANGELOG
@better-auth/redis-storagelistKeys() and clear() to use SCAN instead of KEYS so large keyspaces no longer block the Redis server (#10507)For detailed changes, see CHANGELOG
Thanks to everyone who contributed to this release:
Full changelog: v1.6.25...v1.6.26
better-auth$fetch and $store not being exposed on the Solid client (#10444)modelName was set to another table's schema key (e.g. user.modelName = "account").For detailed changes, see CHANGELOG
Thanks to everyone who contributed to this release:
Full changelog: v1.6.24...v1.6.25
better-authctx) as a third argument to verifyIdToken, enabling custom ID token verifiers to read request headers (#10376)beforeStoreCookie option to the last-login-method plugin for GDPR compliance (#5753)get-session endpoint to include no-store cache control headers, preventing stale session data from being served (#10222)BIGINT as a valid number type, preventing spurious pending changes on rate limiter columns (#10316)useSession({ throw: true }) incorrectly excluding null from its data type (#9787)CookieAttributes index signature type to be more precise (#10442)user.modelName was set to a value that collides with another schema key (#10235)unique and index (#10357)Origin header on cookieless requests, preventing cross-origin abuse (#10368)username and displayUsername) in /sign-up/email and /update-user request bodies (#10453)organization.listMembers failing with "User not found for member" for organizations with more than ~100 members (#10342)advanced.database.generateId is configured, matching the behavior of other models (#10040)getDefaultModelName to prefer exact schema key matches over modelName aliases, preventing adapter queries from being misrouted when a built-in table's name collides with another schema keyFor detailed changes, see CHANGELOG
authunique and index (#10333)relationName values (#10352)auth generate failing when the config file imports the not-yet-generated output file (e.g. on a Convex first run) (#10302)For detailed changes, see CHANGELOG
@better-auth/electron>=36.0.0) (#10440)/electron/init-oauth-proxy forwarding multiple Set-Cookie headers as a single comma-joined string, which caused the browser to drop the transfer-token cookie during OAuth handoff (#9672)For detailed changes, see CHANGELOG
@better-auth/coreAsyncLocalStorage initialization on serverless cold starts (e.g. Cloudflare Workers) (#9862)For detailed changes, see CHANGELOG
@better-auth/ssoidpInitiatedCallbackUrl (#10388)For detailed changes, see CHANGELOG
@better-auth/stripebeforeDeleteOrganization and afterDeleteOrganization hooks not receiving the endpoint context as the second argument (#10190)For detailed changes, see CHANGELOG
Thanks to everyone who contributed to this release:
Full changelog: v1.6.23...v1.6.24
better-authFor detailed changes, see CHANGELOG
@better-auth/drizzle-adapterFor detailed changes, see CHANGELOG
@better-auth/stripeFor detailed changes, see CHANGELOG
authFor detailed changes, see CHANGELOG
Thanks to everyone who contributed to this release:
Full changelog: v1.6.22...v1.6.23
better-authFor detailed changes, see CHANGELOG
@better-auth/scimactive attribute (#10242)For detailed changes, see CHANGELOG
@better-auth/stripeFor detailed changes, see CHANGELOG
authFor detailed changes, see CHANGELOG
Thanks to everyone who contributed to this release:
Full changelog: v1.6.21...v1.6.22
better-authdeviceAuthorization() throwing a ZodError when called without a schema option under Zod v4 (#9939)input: false (#10196)TOO_MANY_ATTEMPTS_REQUEST_NEW_CODE (#10210)displayUsername fallbacks that pass username validation during email sign-up (#10182)For detailed changes, see CHANGELOG
@better-auth/ssojavascript: or data: (#10225)For detailed changes, see CHANGELOG
@better-auth/api-keyX-Forwarded-For spoofing in multi-hop proxy chains (#10203)For detailed changes, see CHANGELOG
authdisableMigration: true to be respected on plugin schema tables during generation and runtime migration (#10198)BETTER_AUTH_SECRET values with 32 characters instead of 16 (#10186)For detailed changes, see CHANGELOG
@better-auth/kysely-adapteradapter.update to return null when no matching row is found (#10180)For detailed changes, see CHANGELOG
@better-auth/stripeFor detailed changes, see CHANGELOG
Thanks to everyone who contributed to this release:
Full changelog: v1.6.20...v1.6.21
better-authAPIError properties (#8734)Max-Age to be capped at expiresIn (#9621)For detailed changes, see CHANGELOG
@better-auth/i18nFor detailed changes, see CHANGELOG
Thanks to everyone who contributed to this release:
Full changelog: v1.6.19...v1.6.20
better-authsendVerificationEmail errors not being surfaced to the client (#8863)last-login-method plugin (#9319)oauth-popup plugin leaking internal OAuth state keys into additionalData (#10067)For detailed changes, see CHANGELOG
authgenerate command not handling a directory path passed to --output (#9564)additionalField default values not being serialized correctly in the Drizzle schema generator (#10048)For detailed changes, see CHANGELOG
@better-auth/drizzle-adapterFor detailed changes, see CHANGELOG
@better-auth/mongo-adapterFor detailed changes, see CHANGELOG
@better-auth/passkeyFor detailed changes, see CHANGELOG
@better-auth/scimFor detailed changes, see CHANGELOG
Thanks to everyone who contributed to this release:
Full changelog: v1.6.18...v1.6.19
better-authgetCookieCache to return null for expired sessions instead of treating stale signed cookies as live sessions.<id>@reddit.invalid) to users with no email, preventing accidental matches with real mailboxes.internalAdapter.reserveVerificationValue to atomically record single-use markers, ensuring only one concurrent caller succeeds for replay-protected operations.incrementOne adapter method and SecondaryStorage.increment for atomic counter updates, enabling strict rate-limit and usage-counter enforcement under concurrent load./delete-user/callback to reject account deletion when the session has been revoked server-side (cookie-only session deployments are unaffected).consume method for custom storage backends to opt into strict enforcement.offline_access scope for refresh token usage.oneTap plugin or socialProviders.google) and reject tokens issued for other applications.set-active and revoke endpoints to only act on sessions the caller holds a signed cookie for, preventing unauthorized session manipulation./oauth2/endsession endpoint to reject cross-site logout requests that carry only a session cookie without a valid id_token_hint.mapProfileToUser available to supply a real one.For detailed changes, see CHANGELOG
@better-auth/ssotrustEmailVerified to treat only a boolean true or the string "true" as a verified email, rejecting the string "false" as unverified.For detailed changes, see CHANGELOG
@better-auth/memory-adapterupdate and delete no-ops on empty filters instead of modifying every row.For detailed changes, see CHANGELOG
@better-auth/oauth-providerFor detailed changes, see CHANGELOG
@better-auth/scimFor detailed changes, see CHANGELOG
@better-auth/api-keyFor detailed changes, see CHANGELOG
@better-auth/drizzle-adapterupdateMany to return the number of rows it affected, as the adapter contract specifies.For detailed changes, see CHANGELOG
@better-auth/electronFor detailed changes, see CHANGELOG
@better-auth/kysely-adapterconsumeOne compatibility with SQL Server.For detailed changes, see CHANGELOG
@better-auth/passkeyFor detailed changes, see CHANGELOG
@better-auth/prisma-adapterdelete operation to surface errors instead of silently reporting success when the failure is not a missing-record error.For detailed changes, see CHANGELOG
@better-auth/redis-storageincrement method for strict enforcement.For detailed changes, see CHANGELOG
Thanks to everyone who contributed to this release:
Full changelog: v1.6.17...v1.6.18
better-authoauthPopup 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)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.<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.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 atomicincrementOne 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./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.consume method for strict enforcement.offline_access scope.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)sub or id field when mapProfileToUser derives the account id (#9987)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)updateSession to accept custom session fields inferred from inferAdditionalFields (#9777)/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)id fields as required (#9704)updateMemberRole to reject unknown or malformed role values, validating them against configured static and dynamic roles (#9962)role.authorize control flow without changing existing authorization behavior (#9677)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./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.For detailed changes, see CHANGELOG
@better-auth/api-keyFor detailed changes, see CHANGELOG
@better-auth/ssotrustEmailVerified 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$app/*, $env/*), Vite asset imports (?raw, ?url), and Cloudflare Workers (cloudflare:workers) virtual-module imports when loading the auth config (#9834)Unsupported() fields when regenerating the Prisma schema (#10011)BigInt or Int when bigint configuration changes (#9729)For detailed changes, see CHANGELOG
@better-auth/expotrustedOrigins (#9990)linkSocial (#9953)For detailed changes, see CHANGELOG
@better-auth/memory-adapterupdate and delete with an empty filter a no-op instead of affecting all rows, and made updateMany return the number of affected rows.For detailed changes, see CHANGELOG
@better-auth/scimFor detailed changes, see CHANGELOG
@better-auth/coreFor detailed changes, see CHANGELOG
@better-auth/drizzle-adapterupdateMany to return the number of rows it affected, as the adapter contract specifies.For detailed changes, see CHANGELOG
@better-auth/electronFor detailed changes, see CHANGELOG
@better-auth/kysely-adapterconsumeOne work on SQL Server.For detailed changes, see CHANGELOG
@better-auth/oauth-providerFor detailed changes, see CHANGELOG
@better-auth/passkeyFor detailed changes, see CHANGELOG
@better-auth/prisma-adapterdelete 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-storageincrement method to Redis secondary storage.For detailed changes, see CHANGELOG
@better-auth/stripereturnUrl against trustedOrigins, and checked all subscriptions on organization deletion (#9971)For detailed changes, see CHANGELOG
Thanks to everyone who contributed to this release:
Full changelog: v1.6.16...v1.6.17
better-authhd (hosted domain) enforcement to verify the hd claim on the verified ID token and callback profile, preventing accounts outside the configured Workspace domain from signing in.verifyAccessToken remote introspection to reject tokens with a missing or mismatching aud claim/admin/create-user and /admin/update-user, and prevent data from overriding protected fields. (#9974)Origin and Referer headers against trustedOrigins even when requests carry no cookies. (#9973)/update-session to reject plugin-managed fields (activeOrganizationId, activeTeamId, impersonatedBy) with a 400 error/update-session and account token routes to immediately reject deleted sessions when cookie cache is enabled alongside database or secondary storage. (#9967)/refresh-token to only trust the account cookie when its userId, providerId, and accountId match the resolved session user.sub.createInvitation and acceptInvitation to validate that all requested team IDs belong to the invitation's organization, preventing cross-organization team membership.oauth_client_id as the user email, preventing all users of the same app from sharing a single email addressdebug_token endpoint, requiring is_valid, a matching app_id, and a client secret for direct sign-in.For detailed changes, see CHANGELOG
@better-auth/oauth-providerauthorization_code from requesting client_credentials tokens./oauth2/continue to derive post-login gate completion from a server-issued session marker rather than the client-submitted postLogin flag.azp claim and a valid client on JWT access tokens, preventing session JWTs from being reported as active access tokens.For detailed changes, see CHANGELOG
@better-auth/ssoAuthnRequest handling to consume the request atomically, preventing replay attacks on concurrent requests. (#9972)For detailed changes, see CHANGELOG
@better-auth/api-key/api-key/create to verify the session against the authoritative store with disableCookieCache: true, preventing revoked sessions from being accepted within the cookie-cache window.For detailed changes, see CHANGELOG
@better-auth/electroncode_challenge_method values.For detailed changes, see CHANGELOG
@better-auth/scimlinkExistingUsers is set, changed org-scoped DELETE to deprovision the user rather than delete the global account, and added canGenerateToken to control SCIM token creation.For detailed changes, see CHANGELOG
Thanks to everyone who contributed to this release:
Full changelog: v1.6.15...v1.6.16