Repository navigation
LLM-733: claude.ai connector with only the URL — CIMD/DCR public clients and a login on /authorize - #376
Merged
Conversation
…nts and a login on /authorize 5 of 13 outside accounts never connected a client, and the claude.ai setup asked them to paste their agent name as Client ID and API key as Client Secret from a one-time screen. Now the connector is added with only the URL. - OAuth metadata advertises CIMD (client_id_metadata_document_supported + "none") and a registration_endpoint; the path-form protected-resource metadata (/.well-known/oauth-protected-resource/mcp) is served. - CIMD: client_id URLs on https://claude.ai or https://claude.com only; the document is not fetched (redirect_uri stays on our fixed allowlist). - DCR at POST /oauth/register: allowed callbacks only; the client_id carries its own HMAC-signed registration, so nothing is stored. - /authorize for these clients shows a login (agent name + dashboard password, POSTed, never in a URL), framed nowhere, with the load-memory block. 5 tries per agent name and 20 per client address per 15 min. The code is bound to the agent that logged in; the token endpoint takes PKCE without a secret for it and issues that agent's token. - The Client ID / Client Secret path is unchanged. claude.com callback added. - Dashboard login and connector login share services/password-login.js. - Signup guide and getting-started template (MEM-151, exact-text patch) say "add the URL, click Connect, log in". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
LLM-733
A claude.ai user can now add the connector with only
https://llm-memory.net/mcp, click Connect, and log in with agent name + password. No Client ID / Client Secret.Why CIMD first, DCR second (Anthropic connector docs, claude.com/docs/connectors/building/authentication): with Advanced settings empty, claude.ai uses a Client ID Metadata Document when the authorization-server metadata advertises both
client_id_metadata_document_supported: trueand"none"as a token auth method, and otherwise falls back to DCR. DCR "registers a new client on every fresh connection". claude.ai also probes/.well-known/oauth-protected-resource/mcpfirst (seen in our request_log, 404 until now).Discovery
registration_endpoint=/oauth/register(/registeris the signup page),token_endpoint_auth_methods_supported: ["none", "client_secret_post"],client_id_metadata_document_supported: true./.well-known/oauth-protected-resource/mcpwithresource=<base>/mcp. The root form is unchanged.Public clients (
services/oauth-public-clients.js)client_idmust be an https URL onhttps://claude.aiorhttps://claude.comwith a path. The document is not fetched: the redirect_uri is held to our fixed allowlist anyway, and fetching would mean an outbound request to a caller-chosen URL.POST /oauth/register(JSON) accepts only allowlisted callbacks and returns a public client (token_endpoint_auth_method: none,grant_types: [authorization_code]). Theclient_idisdcr.+ base64url({r: redirect_uris, t}) +.+ HMAC (bearer secret, domain-separated label). No storage, survives restarts./authorizeholds a DCR client to the callbacks it registered.Login on /authorize
X-Frame-Options: DENY,frame-ancestors 'none',no-store./authorize(form): re-checks the whole OAuth request (hidden fields are untrusted), then rate limits (5 tries per agent name, 20 per client address per 15 min; the address is the last X-Forwarded-For hop, as in request-log.js), thenverifyPasswordLogin(timing-safe for unknown names). Failure re-renders with the name kept and the password never echoed. Success: a 60 s code bound to the agent who logged in, then 303 to the callback.Token endpoint
invalid_clientwhen missing).Unchanged: the Client ID / Client Secret path (wendy, remi, …).
https://claude.com/api/mcp/auth_callbackis added to the allowlist; the docs say claude.ai's callback may move there.Other
services/password-login.js: the dashboard login's name + password check, now shared by/admin/loginand the connector login.Known limit (unchanged, out of scope): the per-agent token never expires, so a login cannot be revoked short of rotating
mcp_oauth_bearer_secret, same as the secret path today.Tests:
oauth-public-client.test.js(16): metadata, DCR accept/refuse, CIMD origin rules, forged/tampered DCR ids, DCR callback binding, wrong/unknown login, CIMD and DCR end-to-end exchange, wrong client/callback/verifier, agent-name code still needs a secret, POST refuses agent-name clients, per-name and per-address limits.password-login.test.js(3). Existingoauth.test.jsunchanged and passing. Probes: removing the DCR callback check or the public-code branch fails the tests. Full suite 312 pass, 2 skipped (opt-in Postgres tests).Not yet tried from a real claude.ai account — that is the first post-deploy check.
Agent: Home
🤖 Generated with Claude Code