# Better Auth v1.7.0 - Product: Better Auth (https://whatsnew.fyi/product/better-auth) - Vendor: Better Auth - Date: 2026-08-18 - Version: v1.7.0 - Original notes: https://github.com/better-auth/better-auth/releases/tag/v1.7.0 - Permalink: https://whatsnew.fyi/product/better-auth/releases/v1.7.0 What's New is an index, not a publisher: every entry below links to the vendor's own release notes, which are the authoritative source. Entries are labelled where they are hand-curated sample data, pre-releases, or drawn from a secondary source such as a developer blog. Reuse: the summaries, labels and curation here are © What's New. Quote freely with attribution and a link back; wholesale republication of the corpus is not permitted — terms: https://whatsnew.fyi/terms. The vendors' own release notes remain their publishers'. --- - **changed** — Move joins configuration from experimental.joins to advanced.database.joins - **changed** — Scope accounts by issuer and require Account.issuer field, with account-specific APIs now selecting through accountId request property - **changed** — OAuth provider identity now sourced from raw verified profiles instead of switching between sub and id at runtime - **changed** — SSO account subjects now use protocol-defined values (OIDC sub claim, SAML NameID) with mapping.id removed from both configurations - **changed** — Support wildcard endpoint matching for captcha - **changed** — Ship MCP as its own package built on the OAuth provider with renamed route helper from withMcpAuth to requireMcpAuth - **changed** — Rename standalone protected-resource factory from mcpHandler to createMcpProtectedRequestHandler - **changed** — Migrate MCP to version 2 with stateless request and response transport - **removed** — Remove MCP-route GET and DELETE exports and session-store options such as redisUrl - **changed** — Change MCP database models with oauthApplication becoming oauthClient and new oauthRefreshToken and oauthClientAssertion tables - **added** — Add OIDC back-channel logout to notify Relying Parties when a user's session ends at the OP - **changed** — Introspection of access token whose bound session has ended now returns active false instead of staying active until token TTL - **changed** — Revoke refresh tokens without offline_access on session end while preserving offline_access refresh tokens for long-lived API access - **changed** — Validate custom description in createInsufficientScopeError against RFC 6750 error_description character set **Blog post:** [Better Auth 1.7](https://better-auth.com/blog/1-7) ##### `better-auth` ###### ❗ Breaking Changes - chore!: move joins to advanced.database.joins ([#10359](https://github.com/better-auth/better-auth/pull/10359)) If you previously set `experimental: { joins: true }`, update your config to: ```ts advanced: { database: { joins: true, }, } ``` Adapters that support native joins use them when enabled. If an adapter cannot return joined data for a query, Better Auth falls back to additional queries and combines the results. Drizzle and Prisma users should ensure their schema includes the required relations (`npx auth@latest generate`). - feat(auth)!: scope accounts by issuer ([#10403](https://github.com/better-auth/better-auth/pull/10403)) This release requires `Account.issuer` but preserves `Account.accountId` as the provider-assigned account identifier. Account-specific APIs select the local `Account.id` through the `accountId` request property; token and provider-profile APIs can instead select the signed account cookie with `useAccountCookie: true`. Credential accounts use `local:credential` and the linked user's stable `id` as their provider identity. OAuth provider identity now comes from raw verified profiles. OpenID Connect discovery uses `sub`, plain OAuth uses `id`, and providers can declare `accountSubject` for another immutable field; Better Auth no longer switches between `sub` and `id` at runtime. `getUserInfo().user` no longer carries provider identity, and `mapProfileToUser` cannot return `id`. Read the selected identity from `accountInfo.account.accountId` instead of `accountInfo.user.id`. The generic `microsoftEntraId` helper now requires a concrete tenant GUID; use the built-in Microsoft provider for multi-tenant authorities. SSO account subjects are now protocol-defined. OIDC uses the verified `sub` claim, and SAML uses the signed `NameID`; `mapping.id` is removed from both configurations. A manual SAML configuration without metadata XML must set `idpMetadata.entityID`, because `samlConfig.issuer` identifies the service provider and no longer acts as the IdP identity. Apply the reviewed account-identity backfill in the Better Auth 1.7 upgrade guide before deploying. The generated schema migration cannot assign trusted issuers or resolve existing identity collisions automatically. - feat(captcha)!: support wildcard endpoint matching ([#10004](https://github.com/better-auth/better-auth/pull/10004)) - feat(mcp)!: ship MCP as its own package built on the OAuth provider ([#9992](https://github.com/better-auth/better-auth/pull/9992)) The shared-auth route helper is renamed from `withMcpAuth` to `requireMcpAuth`. The standalone protected-resource factory is renamed from `mcpHandler` to `createMcpProtectedRequestHandler`; pass one flat `McpProtectedRequestHandlerOptions` object with `issuer`, a single `audience`, optional `jwtVerifyOptions`, token-verification fields, and challenge fields. Its callback receives `accessTokenClaims`. `requireMcpAuth` verifies the access token against the published JWKS, validates DPoP proofs for DPoP-bound tokens, and passes the verified access-token claims to your handler. `createInsufficientScopeError` now validates a custom description against the RFC 6750 `error_description` character set when the error is constructed. Invalid descriptions throw `TypeError("invalid error_description")` before an error can reach resource-challenge serialization. MCP 2026-07-28 uses a stateless request and response transport. Serve MCP routes with version 2 of `@modelcontextprotocol/server`, configure `createMcpHandler` with `legacy: "reject"`, wrap it with `requireMcpAuth`, and export only `POST`. Remove MCP-route `GET` and `DELETE` exports and session-store options such as `redisUrl`. OAuth clients, consent, authorization codes, refresh tokens, and security records remain durable authorization state. To migrate, install `@better-aut _[Truncated at 4000 characters — full notes: https://github.com/better-auth/better-auth/releases/tag/v1.7.0]_