What’s New

Better Auth v1.7.0-rc.2

v1.7.0-rc.2Pre-release
Added 5
  • Add ctx parameter to verifyIdToken
  • Add compound table indexes to database
  • Add beforeStoreCookie option to last-login-method plugin for GDPR compliance
  • Add getOrganization method for metadata-only fetches in organization plugin
  • Add transactional OIDC user resolution to SSO
Changed 12
  • Move joins configuration from experimental.joins to advanced.database.joins
  • Rename Account.accountId to Account.providerAccountId and make Account.issuer required
  • Change account-specific APIs to select Account.id through accountId parameter
  • Use token and provider-profile APIs with useAccountCookie option for signed account cookie selection
  • Use local:credential as credential accounts provider identity
  • OAuth provider identity now comes from raw verified profiles with OIDC using sub and plain OAuth using id
Fixed 3
  • Add no-cache cache control headers to get-session endpoint
  • Recognize BIGINT as valid number type for SQLite in migrations
  • Handle request clone failures in callbacks
Removed 2
  • Remove mapping.id from OIDC and SAML configurations
  • Remove SCIM configuration, client APIs, database schema, and organization-backed Group model
better-auth
❗ Breaking Changes
  • chore!: move joins to advanced.database.joins (#10359)

    If you previously set experimental: { joins: true }, update your config to:

    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)

    This release is breaking. Account.accountId is renamed to Account.providerAccountId, and Account.issuer is required. Account-specific APIs select the local Account.id through accountId; 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.providerAccountId 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(scim)!: decouple provisioning from the organization plugin (#10390)

    This replaces the previous SCIM configuration, client APIs, database schema, and organization-backed Group model. Existing SCIM installations cannot migrate provisioning state in place. Follow the SCIM cutover in the 1.7 upgrade guide, including full directory reprovisioning, before resuming traffic.

    Deferred database side effects now run only after a successful transaction. A rolled-back User update no longer refreshes its cached profile, and a rolled-back bulk session revocation no longer invalidates sessions.

Features
  • feat: add ctx to verifyIdToken (#10376)
  • feat(db): add compound table indexes (#10402)
  • feat(last-login-method): beforeStoreCookie option for GDPR compliance (#5753)
  • feat(organization): add getOrganization for metadata-only fetches (#10397)
  • feat(sso): add transactional OIDC user resolution (#10473)
Bug Fixes
  • chore: widen drizzle-kit peer dependency range (#10299)
  • fix: get-session should have no-cache cache control headers (#10222)
  • fix: recognize BIGINT as valid number type for SQLite in migrations. (#10316)
  • fix(auth): handle request clone failures in callbacks (#10336)
  • fix(client): preserve null in useSession().data type with throw:true (#9787)
  • fix(client): restore auth query lifecycle after remount (#10379)
  • fix(cookies): tighten CookieAttributes index signature type (#10441) (#10442)
  • fix(core): dedup request-state AsyncLocalStorage init to fix intermittent "No request state found" (#9862)
  • fix(core): resolve user.modelName collisions in references and adapter (#10235)
  • fix(db): avoid duplicate unique indexes in kysely migrations (#10357)
  • fix(magic-link, email-otp): force-validate Origin on cookieless send endpoints (#10368)
  • fix(mcp): expose remote auth challenge headers (#10290)
  • fix(open-api): include plugin user fields on sign-up/update bodies (#10453)
  • fix(organization): apply membershipLimit to listMembers user fetch (#10342)
  • fix(organization): let the database generate invitation ids (#10040)
  • fix(siwe): issue addressless nonces (#10234)

For detailed changes, see CHANGELOG

@better-auth/core
❗ Breaking Changes
  • chore!: move joins to advanced.database.joins (#10359)

    If you previously set experimental: { joins: true }, update your config to:

    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)

    This release is breaking. Account.accountId is renamed to Account.providerAccountId, and Account.issuer is required. Account-specific APIs select the local Account.id through accountId; 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.providerAccountId 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(scim)!: decouple provisioning from the organization plugin (#10390)

    This replaces the previous SCIM configuration, client APIs, database schema, and organization-backed Group model. Existing SCIM installations cannot migrate provisioning state in place. Follow the SCIM cutover in the 1.7 upgrade guide, including full directory reprovisioning, before resuming traffic.

    Deferred database side effects now run only after a successful transaction. A rolled-back User update no longer refreshes its cached profile, and a rolled-back bulk session revocation no longer invalidates sessions.

Features
  • feat(db): add compound table indexes (#10402)
  • feat(sso): add transactional OIDC user resolution (#10473)

For detailed changes, see CHANGELOG

@better-auth/drizzle-adapter
❗ Breaking Changes
  • chore!: move joins to advanced.database.joins (#10359)

    If you previously set experimental: { joins: true }, update your config to:

    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).

Features
  • feat(db): add compound table indexes (#10402)
  • feat(drizzle): generate drizzle schema with schema namespace (#7169)

For detailed changes, see CHANGELOG

@better-auth/sso
❗ Breaking Changes
  • feat(auth)!: scope accounts by issuer (#10403)

    This release is breaking. Account.accountId is renamed to Account.providerAccountId, and Account.issuer is required. Account-specific APIs select the local Account.id through accountId; 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.providerAccountId 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.

Features
  • feat(sso): add transactional OIDC user resolution (#10473)
Bug Fixes
  • fix(sso): redirect idp initiated saml flows in split origin deployments (#10388)

For detailed changes, see CHANGELOG

@better-auth/scim
❗ Breaking Changes
  • feat(scim)!: decouple provisioning from the organization plugin (#10390)

    This replaces the previous SCIM configuration, client APIs, database schema, and organization-backed Group model. Existing SCIM installations cannot migrate provisioning state in place. Follow the SCIM cutover in the 1.7 upgrade guide, including full directory reprovisioning, before resuming traffic.

    Deferred database side effects now run only after a successful transaction. A rolled-back User update no longer refreshes its cached profile, and a rolled-back bulk session revocation no longer invalidates sessions.

Features
  • feat(scim): expose active provisioned user links (#10474)

For detailed changes, see CHANGELOG

auth
Features
  • feat(db): add compound table indexes (#10402)
Bug Fixes
  • fix: stub SvelteKit's explicit-environment-variables modules (#10221)
  • fix(cli): avoid duplicate unique indexes in drizzle schema (#10333)
  • fix(cli): disambiguate Drizzle relations with relationName (#10352)
  • fix(cli): recover when auth generate's config self-imports its own output (#10302)

For detailed changes, see CHANGELOG

@better-auth/electron
Bug Fixes
  • fix(electron): forward each Set-Cookie from /electron/init-oauth-proxy individually (#9672)

For detailed changes, see CHANGELOG

@better-auth/kysely-adapter
Bug Fixes
  • fix(kysely-adapter): restore local migration constants (#10377)

For detailed changes, see CHANGELOG

@better-auth/mongo-adapter
Features
  • feat(db): add compound table indexes (#10402)

For detailed changes, see CHANGELOG

@better-auth/oauth-provider
Bug Fixes
  • fix(oauth-provider): defer logout effects until commit (#10472)

For detailed changes, see CHANGELOG

@better-auth/stripe
Bug Fixes
  • fix(organization): pass endpoint context to organization delete hooks (#10190)

For detailed changes, see CHANGELOG

Contributors

Thanks to everyone who contributed to this release:

@akshatmalik-bruh, @ayushman46, @c-nicol, @gaurav-init, @gaurav0107, @GautamBytes, @gustavovalverde, @momomuchu, @OrangeManLi, @paoloricciuti, @ping-maxwell, @shiminshen, @swithek, @Tushar-Khandelwal-2004, @vinay-oppuri

Full changelog: v1.7.0-rc.1...v1.7.0-rc.2

View original

Discussion