You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
claude.ai web (custom connectors): requires OAuth authorization
code flow with user consent screen. Bearer tokens / static API keys
are explicitly not supported. See Anthropic's connector auth docs.
This means: even with Phase 1 (#5) shipped, claude.ai web users still
can't connect to PullMD. Phase 2 closes that gap.
Why phase this separately
OAuth on top of a real user system is straightforward. OAuth without
a user system underneath (which is what was attempted in #4) leads to
inconsistencies and security issues. Sequencing matters:
Shows a consent screen ("claude.ai wants to access PullMD as you,
approve?")
Returns an authorization code to claude.ai
Exchanges code for access token at /oauth/token
Token represents the user, just like an API key from Phase 1
Three integration options with Anthropic
From their docs:
Option A: Dynamic Client Registration (DCR)
Anthropic registers a new OAuth client on each fresh user connection
Requires registration_endpoint in our authorization server metadata
Pro: no manual coordination with Anthropic
Con: can result in many client registrations on our side
Option B: Client ID Metadata Document (CIMD)
A single static client identified by a URL pointing to client metadata
Pro: stable, no proliferation of client records
Con: requires our auth server to support CIMD (a newer pattern)
Option C: oauth_anthropic_creds
We register manually with Anthropic by emailing them client_id and
client_secret
Anthropic stores these and uses them for token exchange on user's behalf
Pro: stable, simple on our side
Con: requires manual coordination with Anthropic, doesn't scale to
forks/multiple deployments
For PullMD as a self-hosted project where users run their own instances, Option B (CIMD) is probably the right fit - it's stable, scales to
many deployments, and doesn't require each PullMD operator to email
Anthropic.
But this needs validation. Anthropic's docs recommend CIMD or
oauth_anthropic_creds over DCR for high-traffic directory entries,
which suggests CIMD is the modern preferred path.
The earlier OAuth attempt in #4 had legitimate code structure but
several blockers that we want to avoid repeating:
/authorize must require user authentication (Phase 1 enables this)
redirect_uri allowlist with exact match (claude.ai's published URLs)
Tokens must carry audience/resource claim
WWW-Authenticate header must include resource_metadata
Trust proxy properly (or use PUBLIC_URL env var for baseUrl)
timingSafeEqual without short-circuit
Test coverage for all auth paths
Rate limiting on /oauth/token and /oauth/authorize
The PKCE implementation skeleton from #4 (S256-only, one-time auth
codes, separate signing keys) is reusable. The flow logic is what
needs to be rebuilt on top of Phase 1's user model.
Open questions
CIMD vs oauth_anthropic_creds: which integration path? Probably
CIMD, but want to validate by looking at how other self-hosted
MCP servers solved this.
Refresh token strategy: rotation on every refresh, or stable
refresh token? Anthropic docs mention "Honor refresh-token rotation
correctly if you rotate tokens." Suggests rotation is supported but
not required.
Token TTL: Phase 1 API keys can be long-lived because they're
user-controlled. OAuth access tokens should be short-lived (e.g. 1
hour) with refresh. Need to settle on numbers.
Multi-instance / horizontal scaling: if PullMD is ever scaled
horizontally, OAuth state (auth codes, refresh tokens) needs shared
storage. SQLite isn't sufficient for that. But probably not a
Phase 2 blocker - single-instance is the realistic deployment model
for now.
Dependencies
Hard dependency on #5 (Phase 1). Don't start Phase 2 work before
Phase 1 is merged and stable.
Scope of work
Rough breakdown (after Phase 1 ships):
AS metadata endpoints (/.well-known/*)
/oauth/authorize endpoint with user-consent screen
Integration with Anthropic (CIMD or oauth_anthropic_creds)
Testing against actual claude.ai web connector
Documentation: README, OAuth setup guide
Tests covering all OAuth flows
Estimated effort: ~1-2 weeks once Phase 1 is in place. Most of the
hard work (user system, sessions) is done by Phase 1.
Discussion
Less urgent than #5. Tracking here so it's not lost. Comments and
prior-art links welcome - if anyone has shipped MCP OAuth against
claude.ai successfully, would love to hear about your setup.
Context
Anthropic's Claude products use different auth mechanisms for MCP
connectors:
Bearer tokens (covered by Architecture: Phase 1 - Multi-user system with sessions + API keys #5 Phase 1 API keys)
code flow with user consent screen. Bearer tokens / static API keys
are explicitly not supported. See Anthropic's connector auth docs.
This means: even with Phase 1 (#5) shipped, claude.ai web users still
can't connect to PullMD. Phase 2 closes that gap.
Why phase this separately
OAuth on top of a real user system is straightforward. OAuth without
a user system underneath (which is what was attempted in #4) leads to
inconsistencies and security issues. Sequencing matters:
system
By the time we tackle Phase 2, the heavy lifting is done. OAuth becomes
a thin layer that:
approve?")
Three integration options with Anthropic
From their docs:
Option A: Dynamic Client Registration (DCR)
registration_endpointin our authorization server metadataOption B: Client ID Metadata Document (CIMD)
Option C: oauth_anthropic_creds
client_secret
forks/multiple deployments
For PullMD as a self-hosted project where users run their own instances,
Option B (CIMD) is probably the right fit - it's stable, scales to
many deployments, and doesn't require each PullMD operator to email
Anthropic.
But this needs validation. Anthropic's docs recommend CIMD or
oauth_anthropic_creds over DCR for high-traffic directory entries,
which suggests CIMD is the modern preferred path.
Required server-side components
On top of Phase 1's user system:
/.well-known/oauth-authorization-server(RFC 8414 metadata)/.well-known/oauth-protected-resource(MCP spec requirement)/oauth/authorize(with user-consent screen)/oauth/token(authorization code exchange + refresh)/oauth/revoke(token revocation)https://claude.ai/api/...andhttps://claude.com/api/...)history")
Security considerations (from #4 review)
The earlier OAuth attempt in #4 had legitimate code structure but
several blockers that we want to avoid repeating:
The PKCE implementation skeleton from #4 (S256-only, one-time auth
codes, separate signing keys) is reusable. The flow logic is what
needs to be rebuilt on top of Phase 1's user model.
Open questions
CIMD vs oauth_anthropic_creds: which integration path? Probably
CIMD, but want to validate by looking at how other self-hosted
MCP servers solved this.
Refresh token strategy: rotation on every refresh, or stable
refresh token? Anthropic docs mention "Honor refresh-token rotation
correctly if you rotate tokens." Suggests rotation is supported but
not required.
Token TTL: Phase 1 API keys can be long-lived because they're
user-controlled. OAuth access tokens should be short-lived (e.g. 1
hour) with refresh. Need to settle on numbers.
Multi-instance / horizontal scaling: if PullMD is ever scaled
horizontally, OAuth state (auth codes, refresh tokens) needs shared
storage. SQLite isn't sufficient for that. But probably not a
Phase 2 blocker - single-instance is the realistic deployment model
for now.
Dependencies
Hard dependency on #5 (Phase 1). Don't start Phase 2 work before
Phase 1 is merged and stable.
Scope of work
Rough breakdown (after Phase 1 ships):
Estimated effort: ~1-2 weeks once Phase 1 is in place. Most of the
hard work (user system, sessions) is done by Phase 1.
Discussion
Less urgent than #5. Tracking here so it's not lost. Comments and
prior-art links welcome - if anyone has shipped MCP OAuth against
claude.ai successfully, would love to hear about your setup.