Every release shipped to Better Auth, straight from GitHub.
Every release shipped to Better Auth, straight from GitHub.
@better-auth/oauth-providerPOST /oauth2/public-client-prelogin with allowPublicClientPrelogin to return a client only when its client_id matches the signed oauth_query, otherwise responding with 401 invalid_client (#12237)oauthProviderResourceClient(auth) defaults to accept issued access tokens when baseURL is only an origin, by including the auth path in the default issuer, JWKS, and introspection URLs (#12234)For detailed changes, see CHANGELOG
@better-auth/prisma-adapterincrementOne and update calls using mode: "insensitive" filters to match case-insensitively on PostgreSQL and MongoDB (#11809)eq null on MongoDB to also match records where the optional field was never set (#11806)For detailed changes, see CHANGELOG
@better-auth/coreFor detailed changes, see CHANGELOG
@better-auth/memory-adapterne null where clauses in the memory adapter to no longer match records where the field was never set (#11806)For detailed changes, see CHANGELOG
@better-auth/ssosaml.clockSkew to the NotBefore and NotOnOrAfter checks in samlify (#12309)For detailed changes, see CHANGELOG
Thanks to everyone who contributed to this release:
Full changelog: v1.7.19...v1.7.20
better-auth/admin/create-user leaving a user without a credential account when creating that account failed, such as a database hook throwing, which made retrying with the same email fail with USER_ALREADY_EXISTS_USE_ANOTHER_EMAIL (#12338)/admin/create-user leaving a user without a credential account when the password was rejected, such as by the Have I Been Pwned plugin, which made retrying with the same email fail with USER_ALREADY_EXISTS_USE_ANOTHER_EMAIL (#12335)get or HEAD (#12336)modelName and field names) leaking into other instances of the same plugin in one process (#12319)/device/token returning invalid_grant instead of invalid_client when validateClient rejects the client_id, matching /device/code and RFC 6749 section 5.2 (#12246)state_mismatch during the daylight saving time fall-back hour when OAuth state is stored in the database and the server's time zone observes daylight saving time (#12320)z.optional(), such as /get-session and Stripe's /subscription/list (#12337)organization.getInvitation to return the INVITATION_NOT_FOUND code for a missing, expired, or non-pending invitation (#12332)listMembers failing with a syntax error on PostgreSQL and MSSQL when the filter matches no members or the offset is past the last member (#12318)active-sessions list in secondary storage being stored without an expiry when every remaining session had less than a second left (#12323)For detailed changes, see CHANGELOG
auth--yes, and prompts appear on stderr so redirecting stdout no longer hides them (#12286)auth info --json --copy now prints valid JSON, auth secret prints only the BETTER_AUTH_SECRET line on stdout, auth login and auth logout messages go to stderr, and auth info shows tips only in an interactive terminal (#12287)--config path reports that the file doesn't exist. auth mcp and auth ai no longer report success after a failed step (#12305)auth mcp setup exit with 1 (#12275)For detailed changes, see CHANGELOG
@better-auth/oauth-providerauth.api.oauth2Consent({ headers, body }) failing with request not found when called from a server route (#12325)prefix.clientSecret getting a different error than other wrong secrets. It now gets the standard invalid_client response: 401 with a WWW-Authenticate: Basic challenge for client_secret_basic, and 400 for client_secret_post (#12327)metadata being stored as a JSON string in its json column. It is now written as an object, so Postgres jsonb operators such as -> and @> work with adapters that pass JSON through natively (Drizzle pg). Rows written as strings by earlier versions are still read (#12328)For detailed changes, see CHANGELOG
@better-auth/coreconsole.error in addition to the configured logger (#12317)getAccessToken and refreshToken returning the expired access token when a provider refuses a token refresh with a 200 status, as GitHub does (#12369)For detailed changes, see CHANGELOG
@better-auth/expoFor detailed changes, see CHANGELOG
@better-auth/mcpresource URLs on .localhost subdomains as non-HTTPS (#12322)For detailed changes, see CHANGELOG
Thanks to everyone who contributed to this release:
Full changelog: v1.7.18...v1.7.19
Action required
- If you use
getTestInstancewithtestWith: "mysql", run a MySQL server at127.0.0.1:3306with therootpassword set toroot_password. (#12244)
better-authsecondaryStorage and storeSessionInDatabase to also revoke sessions created while the revocation is running, except sessions created by a session.delete.after hook, which stay active (#12259)getTestInstance from better-auth/test to close its own Postgres connection pool and SQLite database when the test file finishes, while with Vitest's default sequence.hooks: "stack" your afterAll hooks still run first and can keep using the instance (#12250)getTestInstance with testWith: "mysql" hanging, and added a separate database per instance so several instances can run in one test file (#12244)For detailed changes, see CHANGELOG
@better-auth/coreFor detailed changes, see CHANGELOG
Thanks to everyone who contributed to this release:
Full changelog: v1.7.17...v1.7.18
better-authsession.delete.after hook being treated as revoked during "revoke all sessions" when using secondaryStorage with storeSessionInDatabase (#12212)rememberMe: false (#12181)exp://192.168.*.*:* matching custom-scheme hosts with out-of-range or zero-padded octets (#12217)phoneNumber on sign-up and replacing a verified number when linking an account with an empty phone number (#12219)For detailed changes, see CHANGELOG
@better-auth/expostate parameter when OAuth state is stored in a cookie (#12218)For detailed changes, see CHANGELOG
@better-auth/kysely-adaptercreate with generateId: "serial" leaving an inserted row behind when the table reports no auto-increment id (#12220)For detailed changes, see CHANGELOG
@better-auth/passkeypasskey() plugin is shared between auth instances where only some set baseURL (#12225)For detailed changes, see CHANGELOG
Thanks to everyone who contributed to this release:
Full changelog: v1.7.16...v1.7.17
better-authphoneNumber in the request, social profiles no longer set an unverified number, and verification codes use their own namespace (#12198)/admin/update-user changing phone numbers without permission. It now requires user:set-phone, so add set-phone to custom access control statements (#12198)allowedAttempts under concurrent requests, and bound email change codes to the requesting account (#12198)email_verified value such as "false" as verified, and bound generic OAuth profiles to the ID token subject (#12198)For detailed changes, see CHANGELOG
@better-auth/coredisableSignUp, requireEmailVerification, and overrideUserInfoOnSignIn (#12198)email_verified claims from Cognito and Microsoft Entra ID being read as verified (#12198)For detailed changes, see CHANGELOG
@better-auth/expoFor detailed changes, see CHANGELOG
@better-auth/electronFor detailed changes, see CHANGELOG
@better-auth/passkeyorigin when rpID is set and a wildcard in baseURL.allowedHosts covers it (#12198)userVerification: "required" not being enforced, and applied it to authentication as well as registration (#12198)For detailed changes, see CHANGELOG
@better-auth/stripestripeCustomerId. Server code that sets it through auth.api.updateUser must write it through the database adapter instead (#12198)For detailed changes, see CHANGELOG
@better-auth/kysely-adaptergenerateId: "serial" returning another request's record on connection pools (#12198)For detailed changes, see CHANGELOG
@better-auth/drizzle-adaptergenerateId: "serial" returning another request's record on connection pools (#12198)For detailed changes, see CHANGELOG
Thanks to everyone who contributed to this release:
Full changelog: v1.7.15...v1.7.16
better-authconstructor field in additionalData, failing with a prototype pollution error (#12142)BETTER_AUTH_SECRETS error messages to report the entry position instead of including the entry value (#12098)update-user endpoint to reject data.id with a 400 error instead of attempting to change the user's primary key (#12099)internalAdapter.createSession (#12100)hooks.before hook being dropped from the response, with the endpoint's value winning when both set the same header or cookie (#12145)useSession(useFetch) returning no session during Nuxt SSR when baseURL is inferred from the environment (#12109)genericOAuth HubSpot helper truncating access tokens with reserved characters and now returning null instead of requesting /access-tokens/undefined when no token is present (#12108)/sign-in/username and /is-username-available rejecting usernames that sign-up accepts when validationOrder.username is post-normalization (#12097)For detailed changes, see CHANGELOG
authauth init for Remix and React Router v7 to generate an app/routes/api.auth.$.ts resource route that mounts auth.handler instead of a second auth instance with an unsupported database option (#12118)auth ai overwriting MCP config files it cannot parse, such as those with comments or trailing commas, by leaving them unchanged and printing the config to add manually (#12111)auth login and auth logout re-launching the CLI through npx auth@latest in an endless loop (#12110)auth init hanging during database migration and removed a stray debug line about path aliases (#12148)For detailed changes, see CHANGELOG
@better-auth/stripe/subscription/success returning a 500 for non-string callbackURL and checkoutSessionId query values by rejecting them with a 400 (#12105)/subscription/success to validate callbackURL against trusted origins after replacing {CHECKOUT_SESSION_ID}, preventing redirects to untrusted origins via checkoutSessionId (#12102)For detailed changes, see CHANGELOG
@better-auth/api-key@upstash/redis (#12107)For detailed changes, see CHANGELOG
@better-auth/cimdinvalid_client (#12103)For detailed changes, see CHANGELOG
@better-auth/coreFor detailed changes, see CHANGELOG
Thanks to everyone who contributed to this release:
Full changelog: v1.7.14...v1.7.15
better-authACCOUNT_NOT_FOUND when retrieving an access token after stateless OAuth sign-in links a new provider to an existing user (#11300)For detailed changes, see CHANGELOG
@better-auth/ssosamlConfig.callbackUrl as their ACS URL without spMetadata.metadata, which had failed with invalid_saml_response since 1.6.21 (#11730)For detailed changes, see CHANGELOG
Thanks to everyone who contributed to this release:
Full changelog: v1.6.33...v1.6.34
better-authbase32:<secret> (#12031)For detailed changes, see CHANGELOG
@better-auth/coreloginHint so the Kakao Account login page opens with the ID field prefilled (#12045)For detailed changes, see CHANGELOG
Thanks to everyone who contributed to this release:
Full changelog: v1.7.13...v1.7.14
better-authFor detailed changes, see CHANGELOG
@better-auth/coretokenEndpointAuth: { method } to the Cloudflare provider and deprecated tokenEndpointAuthMethod, which remains supported (#11997)For detailed changes, see CHANGELOG
@better-auth/stripeFor detailed changes, see CHANGELOG
Thanks to everyone who contributed to this release:
Full changelog: v1.7.12...v1.7.13
Action required
- If you use ID token sign-in with a provider that has no
clientId, setclientIdto every client ID your apps sign in with. (#11931)
better-authauth.api.getSession() to keep the original database error as error.cause when the session lookup fails (#11924)For detailed changes, see CHANGELOG
@better-auth/coremapProfileToUser failing to typecheck under exactOptionalPropertyTypes when it returns undefined for name, email, or image (#11918)getUserInfo to no longer receive client-submitted access tokens issued to another Facebook app, and ID tokens missing exp or iat are now rejected (#11919)cause option as a third argument to APIError.from() to keep the underlying error for server-side callers without exposing it in the response (#11924)For detailed changes, see CHANGELOG
@better-auth/mcprequireMcpAuth to accept only OAuth access tokens and reject session JWTs from the JWT plugin, even when they share the issuer and audience (#11934)For detailed changes, see CHANGELOG
@better-auth/ssoexp or iat and providers with an empty client ID, matching social sign-in (#11935)For detailed changes, see CHANGELOG
Thanks to everyone who contributed to this release:
Full changelog: v1.7.11...v1.7.12
better-authint8 columns. (#10719)X-Retry-After value. (#11521)For detailed changes, see CHANGELOG
@better-auth/coreinit returns with options: undefined failing type checks under exactOptionalPropertyTypes. (#11907)<issuer>/.well-known/jwks.json. (#11884)For detailed changes, see CHANGELOG
@better-auth/oauth-provider/oauth2/consent and /oauth2/continue to match their redirect responses. (#10881)For detailed changes, see CHANGELOG
@better-auth/expoFor detailed changes, see CHANGELOG
Thanks to everyone who contributed to this release:
Full changelog: v1.7.10...v1.7.11
better-authbetter-auth/plugins/multi-session and better-auth/test. (#11822)google as the last login method. (#11393)better-auth/plugins/one-tap failing with a not-exported error. (#11696)autoSelect and cancelOnTapOutside settings. (#11820)For detailed changes, see CHANGELOG
@better-auth/oauth-providerprivate_key_jwt clients. (#11695)client_id values to say client not found. (#11799)invalid_grant instead of invalid_client at the token endpoint. (#11176)/oauth2/userinfo, /oauth2/introspect, and /oauth2/revoke. (#11596)For detailed changes, see CHANGELOG
@better-auth/coreFor detailed changes, see CHANGELOG
@better-auth/mongo-adapterfindMany ignoring ID sorting and potentially repeating or skipping paginated results. (#11801)For detailed changes, see CHANGELOG
Thanks to everyone who contributed to this release:
Full changelog: v1.7.9...v1.7.10
better-authonAPIError.onError handlers to finish before responses are sent and log failures without interrupting requests (#11766)For detailed changes, see CHANGELOG
@better-auth/oauth-providerisContinuation to postLogin.shouldRedirect so users can complete authorization after selecting an organization (#11185)For detailed changes, see CHANGELOG
Thanks to everyone who contributed to this release:
Full changelog: v1.7.8...v1.7.9
better-authcustomSession sessions expire or are revoked (#10591)customSession treating session lookup errors as signed-out users (#11391)generateId: "uuid" (#11625)@better-auth/utils and better-call dependency versions across official packages (#11512)lastLoginMethod sign-in failures when cookieName or maxAge is explicitly undefined (#11549)oauthProvider() or mcp() with exactOptionalPropertyTypes (#10266)skipLibCheck: false (#11637)verifyOTP callback (#10698)For detailed changes, see CHANGELOG
@better-auth/coreAsyncLocalStorage initialized after importing Better Auth but before first use, and corrected misleading errors for invalid runtime-provided values in edge and browser fallbacks. (#11712)alg (#11663)generateId: "uuid" (#11625)@better-auth/utils and better-call dependency versions across official packages (#11512)For detailed changes, see CHANGELOG
@better-auth/oauth-provideradminUpdateOAuthClient (#11654)adminCreateOAuthClient (#11655)adminCreateOAuthResource and configured resources (#11655)clientId to clientPrivileges checks for actions on existing OAuth clients (#11658)generateId: "uuid" (#11625)@better-auth/utils and better-call dependency versions across official packages (#11512)oauthProvider() or mcp() with exactOptionalPropertyTypes (#10266)For detailed changes, see CHANGELOG
@better-auth/sso@better-auth/utils and better-call dependency versions across official packages (#11512)mapping values that omit defaulted fields (#11378)callbackUrl (#11743)For detailed changes, see CHANGELOG
@better-auth/scimexternalId (#11167)@better-auth/utils and better-call dependency versions across official packages (#11512)409 instead of 500 when a unique value is already claimed (#11669)null (#11638)For detailed changes, see CHANGELOG
@better-auth/mongo-adapter@better-auth/utils and better-call dependency versions across official packages (#11512)For detailed changes, see CHANGELOG
@better-auth/drizzle-adapter@better-auth/utils and better-call dependency versions across official packages (#11512)For detailed changes, see CHANGELOG
@better-auth/kysely-adapter@better-auth/utils and better-call dependency versions across official packages (#11512)For detailed changes, see CHANGELOG
@better-auth/mcp@better-auth/mcp type errors with exactOptionalPropertyTypes and skipLibCheck: false (#11635)oauthProvider() or mcp() with exactOptionalPropertyTypes (#10266)For detailed changes, see CHANGELOG
@better-auth/api-key@better-auth/utils and better-call dependency versions across official packages (#11512)For detailed changes, see CHANGELOG
@better-auth/cimdFor detailed changes, see CHANGELOG
@better-auth/electron@better-auth/utils and better-call dependency versions across official packages (#11512)For detailed changes, see CHANGELOG
@better-auth/memory-adapter@better-auth/utils and better-call dependency versions across official packages (#11512)For detailed changes, see CHANGELOG
@better-auth/passkey@better-auth/utils and better-call dependency versions across official packages (#11512)For detailed changes, see CHANGELOG
@better-auth/prisma-adapter@better-auth/utils and better-call dependency versions across official packages (#11512)For detailed changes, see CHANGELOG
@better-auth/stripeFor detailed changes, see CHANGELOG
@better-auth/telemetry@better-auth/utils and better-call dependency versions across official packages (#11512)For detailed changes, see CHANGELOG
Thanks to everyone who contributed to this release:
Full changelog: v1.7.7...v1.7.8
better-authMagic Link upgrade: Upgrade servers sharing verification storage together, request new Magic Links, and restart pending OAuth/SAML sign-ins. No database migration is required. See the critical advisory for affected configurations and custom storage changes.
disableSignUp setting. (#11491)Content-Type header. (#11476)Content-Type header. (#11469)For detailed changes, see CHANGELOG
@better-auth/oauth-providervalidateRedirectUri validation for trusted deployments with dynamic OAuth redirect URIs. (#8686)verifyOAuthQueryParams to verify signed authorization queries before rendering a custom consent page. (#11402)For detailed changes, see CHANGELOG
@better-auth/drizzle-adapterFor detailed changes, see CHANGELOG
@better-auth/kysely-adapterconsumeOne deleting a record after a concurrent write invalidates its original condition. (#11495)For detailed changes, see CHANGELOG
Thanks to everyone who contributed to this release:
Full changelog: v1.7.6...v1.7.7
better-authbannedUserMessage function that receives the banned user, allowing sign-in errors to include details such as the ban reason. (#11325)maxPasswordLength are now rejected with PASSWORD_TOO_LONG before hashing or verification. (#11324)For detailed changes, see CHANGELOG
@better-auth/kysely-adapterINTEGER PRIMARY KEY columns without AUTOINCREMENT. (#11374)For detailed changes, see CHANGELOG
@better-auth/prisma-adapterFor detailed changes, see CHANGELOG
@better-auth/coreFor detailed changes, see CHANGELOG
@better-auth/drizzle-adapterFor detailed changes, see CHANGELOG
@better-auth/memory-adapterFor detailed changes, see CHANGELOG
@better-auth/mongo-adapterFor detailed changes, see CHANGELOG
@better-auth/stripeFor detailed changes, see CHANGELOG
authcheck and check schema commands to validate your configured adapter schema on demand. (#11314)For detailed changes, see CHANGELOG
Thanks to everyone who contributed to this release:
Full changelog: v1.7.5...v1.7.6
better-authdatabase.schemaName support for direct PostgreSQL connections. (#11203)better-sqlite3 peer dependency to prevent installation conflicts. (#11209)For detailed changes, see CHANGELOG
@better-auth/coredatabase.schemaName support for direct PostgreSQL connections. (#11203)For detailed changes, see CHANGELOG
@better-auth/cimdFor detailed changes, see CHANGELOG
@better-auth/drizzle-adapterFor detailed changes, see CHANGELOG
@better-auth/kysely-adapterdatabase.schemaName support for direct PostgreSQL connections. (#11203)For detailed changes, see CHANGELOG
Thanks to everyone who contributed to this release:
Full changelog: v1.7.4...v1.7.5
@better-auth/coreFor detailed changes, see CHANGELOG
Thanks to everyone who contributed to this release:
Full changelog: v1.6.32...v1.6.33
better-authFor detailed changes, see CHANGELOG
Thanks to everyone who contributed to this release:
Full changelog: v1.6.31...v1.6.32
better-authexperimental.instrumentation.enabled to disable OpenTelemetry span creation per auth instance. (#11224)testUtils auth helpers. (#11217)For detailed changes, see CHANGELOG
@better-auth/coreexperimental.instrumentation.enabled to disable OpenTelemetry span creation per auth instance. (#11224)For detailed changes, see CHANGELOG
@better-auth/expoFor detailed changes, see CHANGELOG
@better-auth/drizzle-adapterFor detailed changes, see CHANGELOG
@better-auth/test-utilsFor detailed changes, see CHANGELOG
Thanks to everyone who contributed to this release:
Full changelog: v1.7.3...v1.7.4
better-authFor detailed changes, see CHANGELOG
@better-auth/coreFor detailed changes, see CHANGELOG
Thanks to everyone who contributed to this release:
Full changelog: v1.6.30...v1.6.31
Upgrading from 1.7.0–1.7.2:
We restored the 1.6 account core schema to avoid requiring a disruptive backfill for existing users. We recognize the cost to users who already migrated and are committed to keeping the core schema stable throughout v1.
If you applied the 1.7 issuer schema, follow the upgrade guide for the required cleanup. No backfill is needed.
better-authisPasswordCompromised for checking passwords against Have I Been Pwned in custom server-side flows. (#11147)getSession failures when cookie caching is disabled and cached session cookies remain. (#11120)useFetch. (#11084)useFetch integration for the Vue client's useSession hook. (#11085)(providerId, accountId) instead of issuer. (#11153)For detailed changes, see CHANGELOG
@better-auth/coreconsumeOne and incrementOne methods for custom database adapters. (#11189)clientKey and clientSecret options. (#11102)(providerId, accountId) instead of issuer. (#11153)For detailed changes, see CHANGELOG
authauth info to report installed dependency versions instead of declared specifiers. (#11126)auth init to complete when generated setup groups have no dependencies. (#11140)auth upgrade with a clear warning. (#11127)For detailed changes, see CHANGELOG
@better-auth/drizzle-adapterFor detailed changes, see CHANGELOG
@better-auth/test-utilsFor detailed changes, see CHANGELOG
@better-auth/cimdERR_INVALID_IP_ADDRESS on supported Node.js versions. (#10730)For detailed changes, see CHANGELOG
@better-auth/expoFor detailed changes, see CHANGELOG
@better-auth/kysely-adapterFor detailed changes, see CHANGELOG
@better-auth/oauth-providerlocalhost loopback redirects to use ephemeral callback ports. (#11090)For detailed changes, see CHANGELOG
@better-auth/prisma-adapterFor detailed changes, see CHANGELOG
@better-auth/sso(providerId, accountId) instead of issuer. (#11153)For detailed changes, see CHANGELOG
Thanks to everyone who contributed to this release:
Full changelog: v1.7.2...v1.7.3