From 27de1f669cdc93b204189b80909ab61bf22e92e4 Mon Sep 17 00:00:00 2001 From: Taesu Date: Fri, 4 Sep 2026 08:24:24 +0900 Subject: [PATCH] fix(auth): stop warning when account identity scope is omitted --- .../provider-scoped-account-identity.md | 2 +- docs/content/docs/concepts/cli.mdx | 2 +- docs/content/docs/concepts/users-accounts.mdx | 2 +- .../content/docs/guides/1-7-upgrade-guide.mdx | 4 +-- docs/content/docs/plugins/sso.mdx | 2 +- docs/content/docs/reference/options.mdx | 2 +- packages/better-auth/src/auth/base.ts | 6 ---- .../src/context/create-context.test.ts | 34 +++---------------- 8 files changed, 12 insertions(+), 42 deletions(-) diff --git a/.changeset/provider-scoped-account-identity.md b/.changeset/provider-scoped-account-identity.md index 8b77e1695e..1ff8f1ca87 100644 --- a/.changeset/provider-scoped-account-identity.md +++ b/.changeset/provider-scoped-account-identity.md @@ -5,4 +5,4 @@ "better-auth": patch --- -The CLI now generates `account: { identityScope: "provider" }` for new projects. Existing configurations continue to use issuer-scoped identity and log a warning during auth initialization when this option is omitted. +The CLI now generates `account: { identityScope: "provider" }` for new projects. Existing configurations continue to use issuer-scoped identity when this option is omitted. diff --git a/docs/content/docs/concepts/cli.mdx b/docs/content/docs/concepts/cli.mdx index 571501189c..ca5874d243 100644 --- a/docs/content/docs/concepts/cli.mdx +++ b/docs/content/docs/concepts/cli.mdx @@ -133,7 +133,7 @@ npx auth@latest init * `--database` - The database you want to use. Currently, the only supported database is `SQLite`. * `--package-manager` - The package manager you want to use. Currently, the only supported package managers are `npm`, `pnpm`, `yarn`, `bun` (defaults to the manager you used to initialize the CLI). -The generated `auth.ts` includes `account: { identityScope: "provider" }`. Existing configurations that omit this option continue to use issuer scope and log a warning during auth initialization. +The generated `auth.ts` includes `account: { identityScope: "provider" }`. Existing configurations that omit this option continue to use issuer scope. `auth migrate plan` reports this compatibility choice. ## Upgrade diff --git a/docs/content/docs/concepts/users-accounts.mdx b/docs/content/docs/concepts/users-accounts.mdx index 1cded52239..ff77517328 100644 --- a/docs/content/docs/concepts/users-accounts.mdx +++ b/docs/content/docs/concepts/users-accounts.mdx @@ -421,7 +421,7 @@ The `"issuer"` scope stores the verified authority. Provider configurations that The `"provider"` scope stores a deterministic namespace for each configured provider. Provider aliases therefore remain separate accounts. Protocol verification is unchanged by this storage choice. -The `auth init` command selects `"provider"` for new projects. Existing configurations that omit `account.identityScope` continue to use issuer scope and log a warning during auth initialization. Keep the scope consistent across every application instance. Switching scopes on a populated v1.7 database requires an account re-key migration. See the [1.7 upgrade guide](/docs/guides/1-7-upgrade-guide#choose-account-identity-scope) before changing it. +The `auth init` command selects `"provider"` for new projects. Existing configurations that omit `account.identityScope` continue to use issuer scope. `auth migrate plan` reports this compatibility choice. Keep the scope consistent across every application instance. Switching scopes on a populated v1.7 database requires an account re-key migration. See the [1.7 upgrade guide](/docs/guides/1-7-upgrade-guide#choose-account-identity-scope) before changing it. ### List User Accounts diff --git a/docs/content/docs/guides/1-7-upgrade-guide.mdx b/docs/content/docs/guides/1-7-upgrade-guide.mdx index 909e469a0a..e2f257cd52 100644 --- a/docs/content/docs/guides/1-7-upgrade-guide.mdx +++ b/docs/content/docs/guides/1-7-upgrade-guide.mdx @@ -114,7 +114,7 @@ This covers email and password, social login, the generic OAuth plugin, One Tap, ### Choose account identity scope -Every 1.7 account uses the unique key `(issuer, accountId)`. `account.identityScope` controls the value stored in `issuer`. The `"issuer"` scope stores the verified authority, while `"provider"` stores a deterministic namespace for each configured provider. Configurations generated by `auth init` use `"provider"`. Omitting the option continues to use issuer scope and logs a warning during auth initialization. +Every 1.7 account uses the unique key `(issuer, accountId)`. `account.identityScope` controls the value stored in `issuer`. The `"issuer"` scope stores the verified authority, while `"provider"` stores a deterministic namespace for each configured provider. Configurations generated by `auth init` use `"provider"`. Omitting the option continues to use issuer scope. `auth migrate plan` reports this compatibility choice. #### Populated 1.6: preserve provider-scoped account identity @@ -141,7 +141,7 @@ export const auth = betterAuth({ #### Already migrated v1.7: keep issuer identity -Set `account.identityScope` to `"issuer"`. If omitted, the runtime keeps the same identity behavior but logs a warning during auth initialization. In both cases, `auth migrate plan` detects the existing issuer data and `auth migrate apply` makes no account identity changes. +Set `account.identityScope` to `"issuer"`. If omitted, the runtime keeps the same identity behavior. In both cases, `auth migrate plan` detects the existing issuer data and `auth migrate apply` makes no account identity changes. Use this one-line configuration to make the existing behavior explicit: diff --git a/docs/content/docs/plugins/sso.mdx b/docs/content/docs/plugins/sso.mdx index a7abe978ee..74ebfae685 100644 --- a/docs/content/docs/plugins/sso.mdx +++ b/docs/content/docs/plugins/sso.mdx @@ -95,7 +95,7 @@ A redirect URL will be automatically generated using the provider ID. For instan Better Auth verifies the OIDC issuer and `sub` claim before resolving an account. The `mapping` option can map profile fields, but it cannot replace the account subject. -`account.identityScope` only controls the namespace stored after verification. The `"issuer"` scope stores the verified issuer, while `"provider"` stores a deterministic namespace for each provider configuration. Omitting the option continues to use issuer scope and logs a warning during auth initialization. Configurations generated by `auth init` use `"provider"`. +`account.identityScope` only controls the namespace stored after verification. The `"issuer"` scope stores the verified issuer, while `"provider"` stores a deterministic namespace for each provider configuration. Omitting the option continues to use issuer scope. Configurations generated by `auth init` use `"provider"`. Under issuer scope, provider aliases that return the same issuer and subject resolve to one external account. diff --git a/docs/content/docs/reference/options.mdx b/docs/content/docs/reference/options.mdx index 659e0756a8..35c84dfde5 100644 --- a/docs/content/docs/reference/options.mdx +++ b/docs/content/docs/reference/options.mdx @@ -498,7 +498,7 @@ Controls the namespace stored in `issuer` and paired with `accountId` to identif The `"issuer"` scope stores the verified authority. When a provider has no trusted issuer, Better Auth uses a deterministic provider namespace. The `"provider"` scope always stores a deterministic namespace such as `local:oauth:google`. -The `auth init` command generates `account: { identityScope: "provider" }`. Omitting this option continues to use issuer scope and logs a warning during auth initialization. +The `auth init` command generates `account: { identityScope: "provider" }`. Omitting this option continues to use issuer scope. Auth initialization remains silent, while `auth migrate plan` reports this compatibility choice. Use `"provider"` when migrating populated 1.6 data to preserve `(providerId, accountId)` identity. Both scopes use the same Account schema and unique `(issuer, accountId)` index. diff --git a/packages/better-auth/src/auth/base.ts b/packages/better-auth/src/auth/base.ts index 6161513a9c..84426ab4be 100644 --- a/packages/better-auth/src/auth/base.ts +++ b/packages/better-auth/src/auth/base.ts @@ -1,6 +1,5 @@ import type { AuthContext, BetterAuthOptions } from "@better-auth/core"; import { runWithAdapter } from "@better-auth/core/context"; -import { createLogger } from "@better-auth/core/env"; import { BASE_ERROR_CODES, BetterAuthError } from "@better-auth/core/error"; import { getEndpoints, router } from "../api"; import { @@ -16,11 +15,6 @@ export const createBetterAuth = ( options: Options, initFn: (options: Options) => Promise, ): Auth => { - if (options.account?.identityScope === undefined) { - createLogger(options.logger).warn( - 'account.identityScope is omitted; Better Auth v1.7 compatibility mode is using issuer identity. Add account: { identityScope: "issuer" } to make this behavior explicit. For a new database, use account: { identityScope: "provider" } instead. Run auth migrate plan before changing populated account data.', - ); - } const authContext = initFn(options); const { api } = getEndpoints(authContext, options); const errorCodes = options.plugins?.reduce((acc, plugin) => { diff --git a/packages/better-auth/src/context/create-context.test.ts b/packages/better-auth/src/context/create-context.test.ts index a1dcd263de..55388ea12a 100644 --- a/packages/better-auth/src/context/create-context.test.ts +++ b/packages/better-auth/src/context/create-context.test.ts @@ -10,9 +10,6 @@ import { createAuthContext } from "./create-context"; import { getAwaitableValue } from "./helpers"; describe("base context creation", () => { - const omittedIdentityScopeWarning = - 'account.identityScope is omitted; Better Auth v1.7 compatibility mode is using issuer identity. Add account: { identityScope: "issuer" } to make this behavior explicit. For a new database, use account: { identityScope: "provider" } instead. Run auth migrate plan before changing populated account data.'; - const initBase = async (options: Partial = {}) => { const opts: BetterAuthOptions = { baseURL: "http://localhost:3000", @@ -36,7 +33,7 @@ describe("base context creation", () => { vi.unstubAllEnvs(); }); - it("warns once when account.identityScope is omitted", async () => { + it("does not warn when account.identityScope is omitted", async () => { const log = vi.fn(); const baseOptions = { baseURL: "http://localhost:3000", @@ -49,37 +46,16 @@ describe("base context creation", () => { ...baseOptions, database: () => adapter, }); - - expect(log).toHaveBeenCalledTimes(1); - await auth.$context; await auth.$context; - expect(log).toHaveBeenCalledTimes(1); - expect(log).toHaveBeenCalledWith("warn", omittedIdentityScopeWarning); + expect(log).not.toHaveBeenCalledWith( + "warn", + expect.stringContaining("account.identityScope"), + ); expect(findOne).not.toHaveBeenCalled(); expect(findMany).not.toHaveBeenCalled(); }); - it.each([ - "issuer", - "provider", - ] as const)("does not warn when account.identityScope is explicitly %s", async (identityScope) => { - const log = vi.fn(); - const options = { - baseURL: "http://localhost:3000", - logger: { level: "warn", log }, - account: { identityScope }, - } satisfies BetterAuthOptions; - const adapter = await getAdapter(options); - const auth = betterAuth({ - ...options, - database: () => adapter, - }); - await auth.$context; - - expect(log).not.toHaveBeenCalledWith("warn", omittedIdentityScopeWarning); - }); - it("should respect base path", async () => { const res = await initBase({ basePath: "/custom-path",