chore(deps): update better-auth monorepo to v1.6.19#1847
Open
renovate[bot] wants to merge 1 commit into
Open
Conversation
3916d9e to
2c5d79c
Compare
2c5d79c to
6a67797
Compare
6a67797 to
621b8f1
Compare
621b8f1 to
778ef25
Compare
778ef25 to
fa0f05b
Compare
fa0f05b to
dc8f436
Compare
dc8f436 to
c5e8a38
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR contains the following updates:
1.6.11→1.6.19Release Notes
better-auth/better-auth (better-auth)
v1.6.19Compare Source
Patch Changes
#10088
de4aa52Thanks @bytaesu! - Session and account cache cookies near the browser's per-cookie size limit (for example with a longcookiePrefixor many cached fields) are now split into chunks instead of being silently dropped by the browser. A cache too large to fit even when chunked is skipped with a warning rather than failing the request, so reads fall back to the database.#9995
b4b0266Thanks @ElGauchooooo! - The device authorization plugin now accepts an optionaluser_idwhen issuing a device code via/device/code, pre-binding the code to that user. Only the bound user can approve or deny the code, so a publicly visible user code can no longer be claimed by someone else.#10086
5bd5e1cThanks @gustavovalverde! - Refresh-token rotation and token revocation, two-factor backup-code regeneration, device-code claiming, and organization invitation acceptance now work on Prisma. Concurrent or repeat requests in these flows could previously return an error on Prisma instead of the expected result.On MongoDB servers older than 5.0, these flows and other guarded value updates (rate-limit window resets, API-key refills) no longer fail with an empty-update error.
@better-auth/core:incrementOnenow reports a clear error when called with noincrementand noset.#9319
581f827Thanks @ping-maxwell! - fix(last-login-method): include domain when clearing cross-subdomain cookies#10067
8407885Thanks @bytaesu! - Theoauth-popupplugin now ignores internal OAuth state fields passed through itsadditionalDataparameter, soadditionalDataonly ever carries your own custom values.#9555
c1a8a64Thanks @ChrisMGeo! - Fix invalid OpenAPI output for Better Auth callback, session, and passkey routes so client generators can consume the schema.#10071
635f190Thanks @gustavovalverde! - Auth clients exported from wrapper packages can now be emitted in TypeScript declaration builds without extra type annotations.#10070
a787e0bThanks @gustavovalverde! - Single-use verification flows no longer hang on database adapters that use a one-connection pool. This fixes magic-link verification and similar token checks in connection-limited serverless database setups.#9348
c2f718fThanks @ping-maxwell! - fix: cookie cache fallback lookup#8863
7d18175Thanks @ping-maxwell! -sendVerificationEmailwas invoked viarunInBackgroundOrAwait, which could defer work whenadvanced.backgroundTasks.handleris configured (so the handler could return 200 before the email callback finished) and, in the default path, caught and logged errors without rethrowing. User callbacks that throwAPIError(e.g. 429 from a rate limiter) were therefore not reliably reflected in the HTTP response (better-auth/better-auth#8757).Now we await
sendVerificationEmailFnso failures surface to the client with the correct status. The unauthenticated/send-verification-emailpath enforces a constant-time floor (500 ms) so that the response duration does not reveal whether the email belongs to a real unverified user.Updated dependencies [
0895993,5bd5e1c,a787e0b]:v1.6.18Compare Source
Patch Changes
#9315
9ef7240Thanks @GautamBytes! - fix OpenAPI requestBody generation for intersected and default-wrapped body schemas#9583
b21a5f7Thanks @GautamBytes! - Fix plugin-provided client methods and additional session fields not being inferred in composite monorepos.Updated dependencies [
b21a5f7]:v1.6.17Compare Source
Patch Changes
#9993
baeaa00Thanks @gustavovalverde! - When a team had a single open slot, accepting an invitation into it was wrongly rejected as over the member limit and left a dangling membership record. Two invitations accepted into a nearly-full team at the same time could also push it past its limit. Both are fixed.#9482
3e99e6cThanks @bytaesu! -admin.setUserPasswordnow creates a credential account when the target user does not have one, matching the behavior ofresetPassword. Previously the call returnedstatus: truewithout doing anything for users without an existing credential account (e.g., social-only or magic-link signups), so admins migrating users from another auth system or assigning an initial password to a social-only user can now do so directly without poking theaccounttable.96c78c3Thanks @GautamBytes! - Downgrade expected auth validation failures from error logs to warnings.#9993
baeaa00Thanks @gustavovalverde! - Captcha provider verification requests now time out after 10 seconds and fail closed, so a slow or unreachable captcha provider can no longer tie up a request indefinitely.#9993
baeaa00Thanks @gustavovalverde! - A delete-account confirmation link can no longer delete the account more than once when its callback is opened concurrently.#9991
0c3856fThanks @gustavovalverde! - Completing account deletion through/delete-user/callbacknow fails 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.#9993
baeaa00Thanks @gustavovalverde! - Polling for a device-authorization token can no longer redeem the same approved device code more than once when several polls arrive together.#9993
baeaa00Thanks @gustavovalverde! - Submitting the same email OTP from several requests at once can no longer sign in more than once or gain extra tries beyond the attempt limit.#10002
ed7b6c9Thanks @gustavovalverde! - Adding a member to a team that is already at itsmaximumMembersPerTeamlimit is now rejected on every path.addMemberwith ateamIdandadd-team-memberpreviously skipped the limit that invitation acceptance enforced, so they could push a team over its cap. A rejectedaddMemberno longer creates the organization member.#9677
e0a768cThanks @GautamBytes! - Refactorrole.authorizecontrol flow while preserving existing authorization behavior.#9987
7343284Thanks @bytaesu! - Generic OAuth sign-in works again for providers whose userinfo response has nosuboridfield whenmapProfileToUserderives the account id. An emptyidfield now falls back tosub.#9991
0c3856fThanks @gustavovalverde! -getCookieCachenow returnsnullfor an expired session instead of the stale session data. Middleware that calls it to gate access no longer treats an expired signed cookie as a live session.#9993
baeaa00Thanks @gustavovalverde! - The Have I Been Pwned plugin now checks submitted passwords against the breach database on more password-setting endpoints by default, including the email-OTP and phone-number reset-password routes and the admin create-user and set-user-password routes. A breached password can no longer be set through those routes when the plugin is enabled with its default paths.#9987
7343284Thanks @bytaesu! - Preserve the fresh account cookie issued while switching users in the same browser instead of expiring it from stale request cookie state.#9991
0c3856fThanks @gustavovalverde! - Expired MCP access tokens are no longer accepted. A protected MCP resource now rejects a bearer token once it has expired, both on the server and through the remote client. A refresh token is accepted only when the original authorization included theoffline_accessscope.#9991
0c3856fThanks @gustavovalverde! - The multi-sessionset-activeandrevokeendpoints now act only on the session the caller holds a signed cookie for. A request could previously activate or revoke a different session by naming its token in the request body without holding that session's cookie.#9890
d9c526bThanks @bytaesu! - Add an experimentaloauthPopupplugin (withoauthPopupClientandsignIn.popup) for popup-based OAuth sign-in. It lets an app sign in inside a cross-site iframe by completing OAuth in a popup and handing the session token back to the opener, where thebearerplugin authenticates with it. The API may change while it is experimental.#9991
0c3856fThanks @gustavovalverde! - The OIDC provider's RP-initiated logout endpoint (/oauth2/endsession) no longer logs a user out, or revokes their OAuth tokens, in response to a cross-site GET that carries only a session cookie. Logout authenticated by a validid_token_hintis unaffected.#10003
fdef997Thanks @gustavovalverde! - Google One Tap now requires a configured Google client ID and rejects the sign-in callback when none is set. A Google ID token issued for a different application is no longer accepted. Set the client ID on theoneTapplugin or onsocialProviders.google.#9993
baeaa00Thanks @gustavovalverde! - A one-time token can no longer be redeemed for a session more than once when redeemed concurrently.#9993
baeaa00Thanks @gustavovalverde! - A password reset token can no longer change the password more than once when used from several requests at the same time.#9993
baeaa00Thanks @gustavovalverde! - Submitting the same phone-number OTP from several requests at once can no longer sign in more than once or gain extra tries beyond the attempt limit.#9993
baeaa00Thanks @gustavovalverde! - Concurrent requests can no longer slip past the configured rate limit. The in-memory rate-limit store no longer grows without bound, and the database backend removes expired entries on its own. A custom rate-limit storage may implement a new optionalconsumemethod for strict enforcement; without it, the previous behavior is kept and a one-time warning is logged.#9987
7343284Thanks @bytaesu! - Deleting a team no longer breaks its pending invitations. The removed team is dropped from those invitations, which stay valid for their remaining teams or as plain organization-level invitations. Accepting an invitation that still references a missing team fails without consuming the invitation.#9993
baeaa00Thanks @gustavovalverde! - AddinternalAdapter.reserveVerificationValue. It atomically records a single-use marker (such as a replay tombstone) so that exactly one of several concurrent callers succeeds and the rest observe that the marker is already taken. Database-backed verification storage is atomic; secondary-storage-only verification is best-effort.#8760
8960f5fThanks @gustavovalverde! - Session refreshes now avoid duplicate/get-sessionrequests from focus and other browser session events. Client hooks keep stable data references when refetches return unchanged data, reducing unnecessary renders. Unmounting during an in-flight session request no longer leaves session state stuck in a loading state.#9993
baeaa00Thanks @gustavovalverde! - A Sign-In with Ethereum nonce can no longer be used to sign in more than once when submitted from several requests at the same time.#9979
5c289b5Thanks @SferaDev! - Stateless OAuth deployments can now read account info, access tokens, and refresh tokens after different server instances handle sign-in and later requests. Session refresh also keeps the OAuth account cookie instead of clearing it in that case.#9990
1dbf5bbThanks @gustavovalverde! - Hardens how requests are trusted across several flows. Rate limiting is now enforced even when a client IP cannot be determined, instead of being skipped. WhenbaseURLis not configured, password-reset and verification links use the current request's host rather than the host of the first request the server handled, and a request-scopedtrustedOriginscallback no longer affects other concurrent requests. The OAuth proxy, Google One Tap, and the Expo authorization proxy reject redirect and callback targets that are not intrustedOrigins. Google reCAPTCHA and Cloudflare Turnstile accept optionalexpectedActionandallowedHostnamesto reject tokens minted for a different action or hostname. Server-side fetches reject additional reserved IPv6 ranges, and malformed redirect parameters return a 400 instead of a 500.#9993
baeaa00Thanks @gustavovalverde! - An expired two-factor sign-in challenge can no longer complete login with a valid TOTP, OTP, or backup code, and the same challenge can no longer create more than one session when verified concurrently.#9993
baeaa00Thanks @gustavovalverde! - Submitting the same two-factor OTP from several requests at once can no longer sign in more than once or gain extra tries beyond the attempt limit.#9777
59e0ccbThanks @GautamBytes! - ClientupdateSessioncalls now accept inferred custom session fields frominferAdditionalFields.#9962
b803c61Thanks @Bekacru! - Validate roles when updating an organization member. Roles are now normalized into individual tokens and checked against the configured static and dynamic roles, so unknown or malformed role values are rejected instead of being persisted.Updated dependencies [
baeaa00,baeaa00,baeaa00,7343284,baeaa00,baeaa00,fdef997,baeaa00,baeaa00,fdef997,baeaa00,1dbf5bb,fdef997]:v1.6.16Compare Source
Patch Changes
#9974
cb1cbfaThanks @Bekacru! - Guard protected user fields in the admin plugin behind their dedicated permissions./admin/create-usernow requiresuser:set-rolewhen aroleis supplied (top-level or viadata.role), validates requested roles against the configured roles, requiresuser:banfor ban fields passed indata, and no longer letsdataoverrideemail,name, orrole./admin/update-usernow requiresuser:banforbanned/banReason/banExpires(revoking the user's sessions when banning and rejecting self-bans), requires the newuser:set-emailpermission foremail/emailVerified(with email validation, lowercasing, and uniqueness checks), and rejectspasswordupdates in favor of/admin/set-user-password. If you use a custom access control, addset-emailto your statements and grant it (andban) to roles that should be able to change those fields throughupdate-user.#9974
cb1cbfaThanks @Bekacru! - Require a provider account id when signing in through generic OAuth. The default userinfo handler previously fell back to an empty string when the provider response had nosub(orid), and the callback never checked the resolved account id. With certain non-OIDC providers that omitsub, accounts could be stored under the same empty id and a later sign-in could resolve to an existing account. The generic OAuth callback now rejects sign-in when no account id can be resolved, the default userinfo handler returns no profile when neithersubnoridis present, and the built-in OAuth callback also rejects an empty account id.#9974
cb1cbfaThanks @Bekacru! - Scope organization invitation team IDs to the invited organization.createInvitationnow validates that every requestedteamIdbelongs to the invitation's organization regardless of whetherteams.maximumMembersPerTeamis set, andacceptInvitationre-checks each stored team's organization before adding team membership. Previously, with the default unlimited team size, a team ID from another organization could be stored on an invitation and applied on acceptance.#9973
87e7aa5Thanks @gustavovalverde! - Email sign-in and sign-up now validate theOriginorRefererheader againsttrustedOriginseven when the request carries no cookies. Requests that send noOrigin/Refererheader and no Fetch Metadata (such as curl or server-to-server clients) are unaffected. A non-browser client that sends an untrustedOrigin/Refererwithout cookies now receives a 403 and must add that origin totrustedOrigins.#9974
cb1cbfaThanks @Bekacru! - Require/refresh-tokento only trust the account cookie when itsuserId,providerIdand (when supplied)accountIdmatch the resolved session user.#9967
893cf6cThanks @gustavovalverde! - Deleting a session now immediately stops/update-sessionand the account token endpoints (/get-access-token,/refresh-token,/account-info) from accepting it, when cookie cache is enabled alongside a database or secondary storage. Before, these routes kept serving the deleted session from the cached cookie until the cache expired. Deployments that store the session only in the cookie are unaffected.#9974
cb1cbfaThanks @Bekacru! - Bind the SIWE signed message to server state before creating a session. Previously/siwe/verifyonly checked that a nonce row existed for the wallet address and then delegated entirely toverifyMessage. Since the documentedverifyMessage(viem) performs signature recovery only — without inspecting the message body — a signature the wallet produced for a different message (an earlier nonce, another domain, or arbitrary content) could also satisfy verification against a freshly minted nonce.The plugin now parses the ERC-4361 message itself and requires its nonce, domain, address, and chain ID to match the server-issued nonce and configured
domain, and enforces the message'sExpiration Time/Not Beforebounds, before verifying the signature.messagemust now be a valid ERC-4361 message (which all standard SIWE clients produce); non-conforming or mismatched messages are rejected with a 401 (UNAUTHORIZED_SIWE_MESSAGE_MISMATCH,UNAUTHORIZED_SIWE_MESSAGE_EXPIRED, orUNAUTHORIZED_SIWE_MESSAGE_NOT_YET_VALID).verifyMessageimplementations should continue to perform signature recovery only.#9974
cb1cbfaThanks @Bekacru! - Separate SSO provider ids from the account-linking provider namespace used for social/OAuth providers. Previously an SSO provider registered with an id matching a configuredaccountLinking.trustedProvidersentry (e.g.google) was treated as a trusted provider and could implicitly link to an existing verified account with the same email.SSO registration now rejects provider ids that collide with a configured social provider, a
trustedProvidersentry, or a reserved built-in id. In addition, the OIDC and SAML callbacks no longer derive trust from atrustedProvidersname match — SSO trust comes solely from verified domain ownership (domainVerified).handleOAuthUserInfogains atrustProviderByNameoption (defaulttrue, preserving social-provider behavior) that the SSO plugin sets tofalse.#9965
5e49c56Thanks @gustavovalverde! - PassingactiveOrganizationId,activeTeamId, orimpersonatedByto/update-sessionnow returns a 400. Change these plugin-managed session fields through their dedicated endpoints instead, such asorganization.setActive.Updated dependencies [
cb1cbfa,cb1cbfa,cb1cbfa,cb1cbfa,cb1cbfa,cb1cbfa]:v1.6.15Compare Source
Patch Changes
#9875
1012b69Thanks @WilsonnnTan! - The admin plugin'sunbanUser,setRoleandadminUpdateUserendpoints used to callinternalAdapter.updateUserwithout checking that the target user existed, so when the caller passed an unknown id the underlying database error (for example Prisma'sP2025) bubbled up as a generic HTTP 500. those endpoints now mirror the existing guard inbanUser: look the user up viafindUserById, and throw a cleanNOT_FOUND(USER_NOT_FOUND) when no row is returned. Closes #9800.#9865
ad60333Thanks @ping-maxwell! - list-session endpoint now requires a fresh-age session check.#9811
0933c05Thanks @zeroknowledge0x! - Restore Kysely 0.28 and 0.29 compatibility for SQLite dialect introspection. The dialects now mirror Kysely's stable migration table names locally, avoiding strict ESM build failures in Turbopack without forcing consumers onto Kysely 0.29.#9919
b0ddfd3Thanks @gustavovalverde! - Run configured hooks through the whole OAuth sign-in flowhooks.before/hooks.afterconfigured on the auth instance now run for the OAuth authorization that continues after a user signs in, selects an account, or consents. They were being skipped there.Headers or cookies a
hooks.beforesets before returning its own response are no longer dropped, and ahooks.afterthat throws anAPIErrorno longer loses either its cookies or the error's headers.Updated dependencies []:
v1.6.14Compare Source
Patch Changes
#9877
2d9781aThanks @gustavovalverde! - Restore the normal emailed-invitation flow while documenting the stricter verification posture for organization invitations.Client-side
listUserInvitationsnow always requires a verified session email because it enumerates invitation IDs fromsession.user.email. TherequireEmailVerificationOnInvitationoption now controls recipient calls that carry an invitation ID (acceptInvitation,rejectInvitation,getInvitation). When unset, Better Auth keeps the emailed-invitation sign-up flow for built-in opaque invitation IDs, including the default generator oradvanced.database.generateId: "uuid", and requires verified email when invitation IDs are externally controlled or predictable, such asadvanced.database.generateId: "serial"/falseor custom ID generation. Apps that expose invitation IDs outside the invited user's mailbox, expose organization invitation lists to members, or require stricter ownership proof should setrequireEmailVerificationOnInvitation: trueor require verified email before sign-in.#9841
5a2d642Thanks @bytaesu! - Optional fields (required: false) now acceptnull, not just omission. Thegenerated input validation previously rejected
nulleven though the column isnullable, so a nullable field could not be cleared by passing
null.#9845
13abc79Thanks @gustavovalverde! - Harden redirect-URI validation across the OAuth provider plugins.isSafeUrlSchemeandSafeUrlSchemano longer callURL.canParse, which is absent on some supported runtimes and could throw or silently disable the dangerous-scheme check. They now parse with atry/catchfallback.SafeUrlSchemaalso rejects redirect URIs that contain a fragment component, per RFC 6749 §3.1.2.#9806
9d3450aThanks @bytaesu! -getSessionCookienow prefers the__Secure-cookie when both it and a non-secure cookie are present, so the non-secure cookie no longer shadows the current session cookie.Updated dependencies [
13abc79]:v1.6.13Compare Source
Patch Changes
#9813
d3919dcThanks @gustavovalverde! - Support server-sideaccountInfocalls without session headers.auth.api.accountInfonow accepts an optionaluserId, so a trusted server-side caller can read a user's provider profile without constructing session headers. This mirrorsgetAccessTokenandrefreshToken. HTTP callers still require a valid session, and a session always takes precedence over a supplieduserId.The shared "resolve the target user, then fetch a valid access token" logic behind these three endpoints now lives in one place. As part of that, a server-side call that supplies neither a session nor a
userIdreportsUSER_ID_OR_SESSION_REQUIRED(400) consistently, rather thanUNAUTHORIZEDon some endpoints.#9591
5f282bdThanks @Vishesh-Verma-07! - When onlysecondaryStorageis configured (no primary database),storeStateStrategynow defaults to"database"instead of"cookie", preventing oversized-cookie errors on platforms like AWS Lambda. The account cookie that holds OAuth tokens in database-less setups stays enabled, sogetAccessTokenkeeps working.#9818
43c08a2Thanks @gustavovalverde! - Fix two buggyinternalAdapterhelpers.Remove
findAccount(accountId). It looked accounts up by account ID alone, which is unique neither across providers nor across users, so it returned a non-deterministic match. All callers now use a user-scoped or provider-scoped lookup.Replace the ambiguous
deleteSessions(string | string[])with two explicit methods.deleteUserSessions(userId)revokes every session for a user, anddeleteSessions(tokens)revokes sessions by token. The old single-string overload silently treated its argument as a user ID, so a caller that meant to delete one session token could instead wipe all of a user's sessions or quietly match nothing.#9818
43c08a2Thanks @gustavovalverde! - Fix Google One Tap signing in the wrong user when the presented Google account is already linked to someone else. One Tap now resolves identity through the shared OAuth path, so the user who owns the Google subject is signed in, matching the redirect andsignIn.socialflows. Previously it matched a local user by the token's email and used the subject only to decide linking, so a Google credential owned by one user could authenticate a different user who happened to share that email./account-infonow resolves the account from the signed-in user's own linked accounts and accepts an optionalproviderIdto disambiguate when two providers issue the same account ID. A colliding account ID returns a distinctAMBIGUOUS_ACCOUNTerror instead of a misleading "not found", and an account with no configured social provider returns a 400 rather than a 500.#9838
be32012Thanks @gustavovalverde! - Validate the scheme of OAuthredirect_urisin theoidc-providerandmcpplugins.Both plugins previously accepted any string as a
redirect_uriat registration. They now reject thejavascript:,data:, andvbscript:schemes, which are never valid OAuth redirect targets. The@better-auth/oauth-providerpackage already applied this check, so this change brings the two older plugins in line with it.The redirect-URI scheme policy now lives in
@better-auth/coreas a singleSafeUrlSchemaand anisSafeUrlSchemehelper, and the OAuth provider plugins share that one implementation. The client navigation helpers (redirectPlugin, one-tap, and two-factor) also skip navigation when the target uses one of these schemes.The change is non-breaking. The
http,https, loopback, and custom application schemes still register unchanged. Bothoidc-providerandmcpare on the migration path to@better-auth/oauth-provider, which remains the route to its stricter HTTPS-or-loopback policy.#9842
87c1a0cThanks @bytaesu! - You can now clear an organization's logo by passinglogo: nulltocreateOrganizationandupdateOrganization. Previously only a string was accepted, so an existing logo could not be removed.#9822
9c8ded6Thanks @gustavovalverde! - DocumentviewBackupCodesas a server-only function so its API comment no longer reads like an HTTP route.The JSDoc above
auth.api.viewBackupCodesadvertisedPOST /two-factor/view-backup-codes, but the endpoint is server-only: it is not registered on the HTTP router and has no client method. The comment now states that it is callable only from trusted server code and that theuserIdshould come from an authenticated session.#8758
23d7cbfThanks @bytaesu! - ApplyaccountLinking.updateUserInfoOnLinkacross every OAuth link flow.Enabling
updateUserInfoOnLinkonly synced the user's profile when linking through a direct ID token. Linking through the standard OAuth redirect (linkSocial, the generic OAuthoauth2.linkendpoint, and implicit linking on social sign-in) ignored the option, so the name and image never changed. Every link path now honors it.The synced fields match the sign-up path:
name,image, and any fields yourmapProfileToUseradds. The localemailandemailVerifiedare never changed on a link, so linking a provider cannot rebind the account's identity.Implicit linking on social sign-in also returned the pre-update user, so the freshly issued session served stale profile data from its cookie cache until the cache expired. The new session now carries the updated profile.
Updated dependencies [
43c08a2,5c3e248]:v1.6.12Compare Source
Patch Changes
#9603
9bd53e1Thanks @bytaesu! -role.authorizenow treats empty action lists ([]or{ actions: [] }) as unauthorized, and evaluates each requested resource under theORconnector before returning the result.#9702
23dbe1aThanks @bytaesu! - Banned users signing in with an OAuth provider now redirect to theerrorCallbackURLpassed tosignIn.social, with?error=BANNED_USER&error_description=<message>in the query string. Previously the redirect went to the auth server's default error page with?error=banned, which broke multi-domain deployments where the auth host and frontend host differ. Theoauth-proxy, SSO OIDC, and SAML callbacks now also redirect hook rejections to the error URL (previously returned JSON 403), andoauth-proxyURL-encodes theerrorquery value across all its redirects.#9596
7a12072Thanks @bytaesu! - Email OTP sign-in no longer fails with a missing-captcha-token error under the default captcha settings. If you intentionally want captcha on email OTP sign-in, add/sign-in/email-otptocaptcha({ endpoints }).#9614
09a1d50Thanks @bytaesu! -changeEmailno longer silently returns{ status: true }when the flow cannot complete: ifemailVerification.sendVerificationEmailis missing for a verified user, the request now fails with a 400 error.callbackURLvalues are also URL-encoded, so callbacks that carry their own query string survive the round trip through verify-email links.#9617 [
a6f144a](https://redirect.github.com/better-auth/bConfiguration
📅 Schedule: (UTC)
🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.
♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.
🔕 Ignore: Close this PR and you won't be reminded about this update again.
This PR was generated by Mend Renovate. View the repository job log.