Repository navigation
Upgrade Better Auth to 1.7.10 so MCP clients can register - #324
Merged
Merged
Conversation
Better Auth 1.7.8 added `clientRegistrationDefaultApplicationType`, which accepts the registration that Cursor and Claude Code send without an `application_type`. Upgrade `better-auth` and `@better-auth/oauth-provider` together, set that option to "infer", and redo the 1.7 settings that the rollback in #218 undid. Closes #266 Co-authored-by: Cursor <cursoragent@cursor.com>
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Better Auth 1.7.10 requires zod 4.5.4 or later, and zod 4.5 writes nullable fields as `type: [..., "null"]` and requires seconds in date-time patterns. Only tool output schemas change. Co-authored-by: Cursor <cursoragent@cursor.com>
This branch was successfully deployed
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.
Summary
Upgrades
better-authand@better-auth/oauth-providerfrom 1.6.27 to 1.7.10. Closes #266.We rolled back from 1.7 in #218 because it rejected the OAuth client registration that Cursor and Claude Code send. The upstream fix (better-auth/better-auth#10956) shipped in 1.7.8. It adds a
clientRegistrationDefaultApplicationTypesetting, and this PR sets it to"infer".The upgrade also clears GHSA-p2fr-6hmx-4528 from
npm audit. It replaces #308, the Dependabot PR that bumped only@better-auth/oauth-providerto 1.7.0, the version that broke registration.What changed
Settings in
web/lib/auth.tsclientRegistrationDefaultApplicationType: "infer". When a client leaves outapplication_type, Better Auth registers it asnativeif any callback uses a custom scheme (Cursor'scursor://) or a loopback address (Claude Code'shttp://localhost:3118). Clients with only https callbacks stayweb, and every callback of a native client must still pass the native rules.resources: [mcpResourceAudience]replacesvalidAudiences, which 1.7 removed. Better Auth stores the audience as a row inoauth_resource.enforcePerClientResources: false. In 1.7, each client must be linked to the audience inoauth_client_resourceby default. Every client registered on staging and production under 1.6 has no link and would getinvalid_target, so existing Cursor and Claude Code connections would break on deploy. With one audience, the link restricts nothing. The upstream upgrade guide recommends this setting for servers that accept dynamic registration.0044already created, and removed thesilenceWarningsoption, which 1.7 removed along with the warning it silenced.Other code
web/lib/mcp/auth.ts:verifyAccessTokenis renamedverifyBearerTokenin 1.7. The options are the same.web/package.json: removed the@better-auth/coreoverride that kept every Better Auth package on 1.6. All of them now resolve to 1.7.10.Database
No migration.
npm run db:generate-auth-schemaagainst 1.7.10 produces the same tables we already have, apart from formatting, anddrizzle-kit generatereports no changes.account.issuerstays as it is. Only 1.7.0 through 1.7.2 wrote it, and 1.7.3 went back to identifying accounts byproviderIdandaccountId. Migration0045already made the column nullable, which is all upstream requires. I left the column in place so that rolling the code back doesn't fail on a missing column. Dropping it can be a later cleanup.Test and seed setup
1.7.10 changes two things that only matter when tables are wiped while the server keeps running, which the integration tests and
make db-reseedboth do:oauth_resourcerow only once per server process. The newseedMcpResourceputs it back afterresetDb()and in the workspace seed. Without it, every MCP token request after a reset failed withinvalid_target.clearAllno longer emptiesjwks, so tokens keep being signed with a key the route already knows. Without this, MCP calls after a reset returned 401.Tests
cursor://anysphere.cursor-mcp/oauth/callback, and noapplication_type. It checks that the client is stored asnativeand that the authorize step accepts thecursor://callback.http://localhost:3118/callback.http://callback is rejected withinvalid_redirect_uri.getMcpAccessTokeninserts clients the way 1.6 stored them (no audience link, noapplication_type), so every MCP integration test also checks that pre-upgrade clients keep working.zod 4.6
Better Auth 1.7.10 requires
zod4.5.4 or later, sozodmoves from 4.4.3 to 4.6.7. Two behavior changes arrived in zod 4.5.0:type: ["string", "null"]instead ofanyOf. This changes the output schemas of 31 MCP tools; no tool input schema changes.mcp-catalog.snapshot.jsonis regenerated.isoDateTimenow requires seconds, as RFC 3339 does.2026-10-16T12:00Zwas accepted before and is now rejected. Of our request fields, onlyacquired_atandfile_created_aton the run and file endpoints use it. The watcher formats both with Python'sisoformat(), which always includes seconds.No changelog entry. Users shouldn't notice any change, because Cursor and Claude Code already work on 1.6 and the watcher already sends seconds.
Google sign-in on preview deployments
Google sign-in on this PR's preview fails with
state_mismatchon staging's login page. That's expected until staging runs 1.7:oAuthProxyplugin./oauth-proxy-callbackto/callback/:id/oauth-proxy./login?error=state_mismatch.After this merges, staging handles 1.7 previews. Previews of branches still on 1.6 hit the same error until they merge
staging(currently #246), and so does a localmake devthat usesOAUTH_PROXY_URLwith a different Better Auth version than staging.Before merging
Upstream asks for a check for duplicate account keys before upgrading, because 1.7 rejects a sign-in when more than one row matches. Our schema has no unique index on these columns, so please run this on staging and production and confirm it returns no rows:
Test plan
make checknpm auditno longer reports GHSA-p2fr-6hmx-4528. The remaining high-severity findings come from thebraceschain and were already onstaging.alice@example.comworks, and the session reports the admin flagnative, and an https-only client returns 201 aswebget_mereturned the signed-in userclaude mcp login data-hub-staging