Repository navigation
feat(auth): migrate to @better-auth/mcp; fix OAuth on fresh installs - #20
Merged
Merged
Conversation
better-auth 1.7 moved the MCP plugin out of core into @better-auth/mcp, an OAuth 2.1 provider built on @better-auth/oauth-provider. Move to it (better-auth, @better-auth/mcp and @better-auth/oauth-provider ~1.7.7): - Access tokens are EdDSA-signed JWTs bound to `<BETTER_AUTH_URL>/mcp` (or the bare origin). brainAuth verifies them locally against the server's own JWKS instead of looking up a session. - Discovery: RFC 9728 protected resource metadata, RFC 8414 metadata at both /.well-known/oauth-authorization-server and its /api/auth issuer path, OIDC config. 401s carry a WWW-Authenticate resource_metadata challenge so MCP clients can start the flow. - New /consent page; the sign-in page resumes /oauth2/authorize. Dynamic client registration stays enabled for Claude and other MCP clients; HTTPS redirect URIs are now required. Fix two install problems found along the way: - The auth tables were never created, so OAuth didn't work on a fresh install. `kb start` now creates or upgrades the schema on every start. On databases from the old plugin it moves the colliding tables and their indexes aside as legacy_* (nothing is dropped) before migrating; accounts and sessions are kept. - With public sign-up disabled there was no way to create the owner account. Add `kb auth add-user <email>` (masked prompt or --password-stdin). Tests: the real provider in-process (sign-up refused, wrong password, anonymous authorize, full flow + refresh, bare-origin resource, consent denied, forged/tampered tokens), an upgrade from a pre-1.7 production schema fixture, and the package smoke test now drives the full Claude connector flow over HTTP: 401 challenge, discovery, registration, sign-in, browser redirect to consent, token, then MCP initialize. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| console.log(`Created ${user.email}. Sign in with it when an MCP client asks you to authorize.`); | ||
| process.exit(0); | ||
| } catch (err) { | ||
| console.error(`kb auth add-user: ${err.message}`); |
| // 2. OAuth schema: create it on first run, upgrade it after better-auth updates | ||
| const archivedAuthTables = await migrateAuthSchema(); | ||
| if (archivedAuthTables.length) { | ||
| console.log(`OAuth schema upgraded; previous OAuth clients/tokens kept in ${archivedAuthTables.join(', ')}. Reconnect MCP clients.`); |
Comment on lines
+121
to
+123
| app.get('/consent', (req, res) => { | ||
| res.sendFile(join(__dirname, 'public', 'consent.html')); | ||
| }); |
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.
Why
better-auth 1.7 moved the MCP plugin out of core into
@better-auth/mcp, an OAuth 2.1 provider built on@better-auth/oauth-provider. We were pinned to 1.6.x to keep the old API. This moves to the supported plugin, and fixes two install problems found along the way.What changes
<BETTER_AUTH_URL>/mcp(or the bare origin). The auth middleware verifies them locally against the server's own JWKS./.well-known/oauth-authorization-serverand its/api/authissuer path, and OIDC config. A 401 now includes aWWW-Authenticate: Bearer resource_metadata=…challenge so MCP clients can start OAuth./consentpage (shows which client is asking, Allow/Deny). The sign-in page resumes/oauth2/authorize. Dynamic client registration stays enabled for Claude; HTTPS redirect URIs are now required.kb startnow creates or upgrades the schema on every start.legacy_*(nothing dropped) before migrating. Accounts and sessions are kept; MCP clients must reconnect.kb auth add-user <email>(masked prompt or--password-stdin) is the way to create one.better-auth,@better-auth/mcpand@better-auth/oauth-providerpinned to~1.7.7.Testing
tests/auth-oauth.test.js: the real provider in-process. Sign-up refused, wrong password, anonymous authorize gets no code, full flow + refresh, bare-origin resource, consent denied, forged/tampered tokens rejected.tests/auth-migrate.test.js: upgrade from a pre-1.7 production schema fixture (schema only) with a user and legacy rows. Legacy tables and indexes are archived with rows intact, the run is idempotent, the existing user signs in and authorizes, and old tokens are rejected. Caught an index-name collision that would have failed the upgrade.initializewith the token and REST access. It also checks public sign-up is refused.auth.db: 1 user, 8 sessions, 22 old clients and 562 old tokens preserved (archived), integrity ok, 0 FK violations, second run a no-op.npm test: 140/140.npm audit --omit=dev: 0 vulnerabilities.Upgrade note
After deploying, previously connected MCP clients (e.g. the Claude connector) must be removed and re-added.
🤖 Generated with Claude Code