fix(auth): upgrade better-auth to 1.7.1, verify account.issuer derives automatically - #1015
Conversation
…s automatically Bumps the better-auth dev dependency to 1.7.1 and moves the stale ^1.3.29 peer floor to ^1.4.0 (the release line where the index:true flags #937 depends on first shipped). Since deriveAuthLists reads better-auth's own getAuthTables() (#987/#997), the new required account.issuer column reaches the generated schema automatically — verified with a new regression test rather than assuming it. The table-level @@unique([issuer, accountId]) constraint better-auth 1.7 also declares is not emitted yet: that needs table-level db.indexes derivation (#985), which hasn't landed, so per #986's own triage note this stops short of duplicating that work. Collateral of the bump: better-auth 1.7 split the MCP plugin into a separate @better-auth/mcp package (added as an optional peer) with a new required `resource` option and a substantially redesigned OAuth table set, which needed the mcp-plugin tests and example config updated to match. Also fixes a pre-existing gap where deriveAuthLists didn't thread a static defaultValue through for number-typed fields, surfaced by the MCP plugin's expanded schema. Closes #986 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QtaxBvCjLsZcm7YiSmpteJ
🦋 Changeset detectedLatest commit: a5234d9 The changes in this PR will be included in the next version bump. This PR includes changesets to release 9 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
Deployment failed for project stack-docs with the following error: Learn More: https://vercel.com/open-saas?upgradeToPro=build-rate-limit |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 12a6c74dcc
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…longside mcp() CI caught two real bugs in the earlier commit that only surface with a live better-auth 1.7 instance: 1. deriveAuthLists silently dropped createdAt/updatedAt for any plugin table that doesn't declare both symmetrically (several of the MCP plugin's new OAuth tables declare only createdAt). The column vanished entirely rather than falling back to an ordinary field, so the first real write supplying it crashed with a Prisma "Unknown argument" error — which is exactly what happened when better-auth's own OAuth Provider seeds an oauthResource row during betterAuth() init. Fixed by only relying on the list-level db.timestamps auto-columns when a model declares both fields; otherwise the field derives normally like any other column. 2. better-auth 1.7's mcp() is built on the OAuth Provider, which issues JWT-based access tokens and now hard-requires better-auth's own jwt() plugin registered alongside it (throws BetterAuthError: jwt_config otherwise). Added it to the e2e test fixture, examples/mcp-demo, and the three places docs showed betterAuthPlugins: [mcp(...)]. Also rewrote the e2e test's OAuth row assertions for the new table/field shapes (oauthApplication -> oauthClient, no more combined access+refresh token row) and made its baseURL explicit, which the OAuth Provider now needs to resolve at init and which this test's in-process createAuth() doesn't get from the CLI subprocess's BETTER_AUTH_URL. Verified locally: full auth unit suite plus both e2e suites (RUN_MCP_OAUTH_CASCADE_E2E=1, RUN_RATE_LIMIT_E2E=1) green, full monorepo build/lint/format clean. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QtaxBvCjLsZcm7YiSmpteJ
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Addresses automated review feedback on PR #1015: - docs/content/reference/auth.md's MCP snippets used an undocumented APP_URL env var (would resolve to undefined/api/mcp); switched to NEXT_PUBLIC_APP_URL with the localhost fallback, matching this file's own existing baseURL convention. - The changeset's account.issuer backfill SQL used || for concatenation, which is logical OR on MySQL by default and would silently write 0/1 instead of the intended string. Added a MySQL-safe CONCAT variant alongside the PostgreSQL/SQLite one, and a note to substitute the project's actual (possibly renamed/schema-qualified) account table name. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QtaxBvCjLsZcm7YiSmpteJ
…-auth/core, missing consentPage The full turbo test run (which builds every example, unlike the fast local `pnpm build`/`pnpm test` I'd been checking) surfaced three more real problems in examples/mcp-demo, all collateral of the better-auth 1.7 MCP redesign: 1. mcp-demo's opensaas.config.ts imports `jwt` from 'better-auth/plugins' directly, but the package never declared `better-auth` as its own dependency (relying on incidental hoisting, which Next.js/Turbopack's strict per-package module resolution doesn't honor). Added it. 2. better-auth 1.7.1's own published packages disagree on their `@better-auth/utils` dependency (better-auth pins exactly 0.4.2, better-call - shared by @better-auth/core/oauth-provider/mcp - wants ^0.5.0), so pnpm resolved two physical @better-auth/core instances. jwt() and mcp() ended up typed against different instances, so betterAuthPlugins: [jwt(), mcp(...)] failed to type-check with a structural BetterAuthPlugin mismatch even though both were configured correctly. Added a root pnpm.overrides pin forcing one instance. 3. better-auth 1.7's mcp() also requires a `consentPage` option (the page where a user approves/denies an MCP client's requested scopes), alongside the resource option already added. Missing it is a type error, not a runtime throw like the missing jwt()/resource cases, so it only surfaced once (1) and (2) were fixed and the build actually reached type-checking. Added it everywhere resource was added. Verified with the actual commands CI runs rather than the narrower ones I'd been using locally: `pnpm turbo run build` and `pnpm turbo run test` across all 24 workspace packages/examples, both green (32/32 tasks). Also re-ran the full auth unit suite and both e2e suites. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QtaxBvCjLsZcm7YiSmpteJ
Coverage Report for Core Package Coverage (./packages/core)
File CoverageNo changed files found. |
Coverage Report for UI Package Coverage (./packages/ui)
File CoverageNo changed files found. |
Coverage Report for CLI Package Coverage (./packages/cli)
File CoverageNo changed files found. |
Coverage Report for Auth Package Coverage (./packages/auth)
File Coverage
|
||||||||||||||||||||||||||||||||||||||||||||
Coverage Report for Storage Package Coverage (./packages/storage)
File CoverageNo changed files found. |
Coverage Report for RAG Package Coverage (./packages/rag)
File CoverageNo changed files found. |
Coverage Report for Storage S3 Package Coverage (./packages/storage-s3)
File CoverageNo changed files found. |
Coverage Report for Storage Vercel Package Coverage (./packages/storage-vercel)
File CoverageNo changed files found. |
Summary
packages/auth'sbetter-authdev dependency from^1.6.25to^1.7.1, and moves the peer range off the stale^1.3.29floor to^1.4.0(the release line where theindex: trueflags auth: three indexes better-auth creates are never emitted — and ADR-0007's stated rationale for omitting the FK index is wrong #937 depends on first shipped).deriveAuthListsderives the Auth lists from better-auth's owngetAuthTables()(auth: derive the auth lists from better-auth's own table definitions instead of hand-mirroring them #987/fix(auth): derive Auth lists from better-auth's own getAuthTables output #997), the new requiredaccount.issuercolumn better-auth 1.7 adds reaches the generated schema automatically, with no derivation code changes — verified against real generated output with a new regression test (generated-fk-shape.test.ts) rather than assumed.FIELD_ORDERupdated to placeissuernext toaccountId/providerId(the fields it forms a composite constraint with).@@unique([issuer, accountId])constraint onaccount. The stack only derives field-levelunique/indextoday — table-leveldb.indexesderivation is auth: no seam for an app to declare its own indexes on a derived auth list #985, which hasn't landed. Per auth: upgrade better-auth to 1.7.1 — new requiredaccount.issuercolumn, new@@unique([issuer, accountId]), and a stale^1.3.29peer floor #986's own triage comment ("if auth: no seam for an app to declare its own indexes on a derived auth list #985 has not landed when you pick this up, say so and stop rather than duplicating it"), this PR does not attempt that part.createLocalAccountIssuer/createOAuthAccountIssuerhelpers, and a heads-up that the composite unique constraint is still pending on auth: no seam for an app to declare its own indexes on a derived auth list #985.Collateral of the version bump (needed to make 1.7.1 actually build/test)
better-auth 1.7 split the
mcpplugin out ofbetter-auth/pluginsinto a separate@better-auth/mcppackage, rebuilt on the OAuth Provider RFC 8707/9728 resource model:@opensaas/stack-auth/pluginsnow re-exportsmcpfrom@better-auth/mcp(added as an optional peer dependency — only needed by apps using MCP).mcp()now requires aresourceoption (the canonical protected-resource URL). Updated the MCP how-to guide, the auth reference doc, rootCLAUDE.md, andexamples/mcp-demo's config to pass it.oauthApplication/oauthAccessToken/oauthConsent→oauthClient/oauthAccessToken/oauthConsent/oauthRefreshToken/oauthResource/oauthClientResource/oauthClientAssertion). Since the derivation is schema-driven this needed no production code changes beyond the above, but the MCP-plugin-specific tests (plugin-table-derivation.test.ts,generated-fk-shape.test.ts,auth-lists-drift.test.ts) were updated to match the new table/field shapes.number-typed fields with static defaults):deriveAuthLists's scalar-field builder wasn't threadingdefaultValuethrough fornumberfields (integer()/bigInt()), unlikestring/boolean. One-line fix, matching existing behavior.Examples
examples/auth-demo,examples/starter-auth:better-authbumped to^1.7.1.examples/starter-auth's committedprisma/schema.prismaregenerated — this also picks up the pre-existinguserId @map/@@indexfixes from auth: derived Session/Account FK column generates asuser, notuserId— every adoption diffs dirty #935/auth: three indexes better-auth creates are never emitted — and ADR-0007's stated rationale for omitting the FK index is wrong #937 that had never been regenerated into this example's checked-in schema.examples/mcp-demo'sopensaas.config.tsnow passesresourcetomcp().Test plan
pnpm testinpackages/auth— 16 files, 271 passed, 3 skippedpnpm testinpackages/coreandpackages/cli— unaffected, all greenpnpm build(full monorepo) — cleanpnpm lint— no new warnings/errorspnpm manypkg fix/pnpm format— appliedaccount.issuer String(required, non-nullable), positioned afterproviderId; composite unique intentionally not emitted (confirmed and asserted in the new test)examples/starter-authandexamples/auth-demoschemas end-to-end;examples/mcp-demogenerate succeeds with the newmcp({ resource })config@opensaas/stack-auth: minor)Closes #986
Generated by Claude Code