Skip to content

feat(server): accept OAuth access tokens on the HTTP transport - #100

Merged
ysyneu merged 6 commits into
mainfrom
feat/mcp-oauth
Oct 8, 2026
Merged

ysyneu merged 6 commits into
mainfrom
feat/mcp-oauth

Conversation

@ysyneu

@ysyneu ysyneu commented Oct 8, 2026

Copy link
Copy Markdown
Collaborator

Makes the HTTP transport an OAuth 2.0 protected resource (MCP authorization spec 2025-11-25). Hosts that can't send a static header, such as claude.ai, Claude Desktop and ChatGPT connectors, can then sign in through the browser.

  • A request with no credential gets 401 plus WWW-Authenticate: Bearer resource_metadata="<origin>/.well-known/oauth-protected-resource<path>".
  • RFC 9728 metadata is served at /.well-known/oauth-protected-resource/mcp (also /flashduty and the root path).
    • resource comes from the request origin and respects X-Forwarded-Proto / X-Forwarded-Host.
    • authorization_servers is the configured Flashduty API base URL.
  • A Bearer credential prefixed oauth: is forwarded to the API as an access token through go-flashduty NewClientWithAccessToken.
    • It ignores the ?base_url= override, because a token is only valid at the API that issued it.
    • It uses its own client cache key.
  • Any other Bearer value, and ?app_key=, still work as an APP key. Stdio mode is unchanged.
  • go-flashduty is bumped to the commit that adds NewClientWithAccessToken (feat: add NewClientWithAccessToken for Bearer-token authentication go-flashduty#87). Before merging to main, re-pin it to the tagged release.
  • Two required pieces live outside this repo. The authorization server (CIMD client registration, PKCE S256) and the consent page ship separately in the Flashduty platform. The OAuth path only works end to end once those are deployed.

Tests: make check passes (fmt, lint 0 issues, go test -race, build). New tests in internal/flashduty/server_test.go cover:

  • the 401 challenge, including behind a proxy and on the legacy path;
  • the metadata JSON;
  • credential routing for OAuth versus APP key;
  • base_url being ignored for OAuth tokens.

🤖 Generated with Claude Code

ysyneu added 6 commits October 8, 2026 01:26
Act as an OAuth 2.0 protected resource for MCP clients that cannot send a
static header (claude.ai, Claude Desktop and ChatGPT connectors):

- Requests to /mcp or /flashduty without a credential get 401 with a
  WWW-Authenticate challenge carrying resource_metadata.
- Serve RFC 9728 protected resource metadata at
  /.well-known/oauth-protected-resource[/mcp|/flashduty]; the resource is
  derived from the request origin (X-Forwarded-Proto/Host aware) and the
  authorization server is the configured Flashduty API base URL.
- Bearer credentials prefixed with oauth: are forwarded to the API as
  bearer access tokens via go-flashduty NewClientWithAccessToken; they
  ignore the ?base_url= override and use a separate client cache key.
  Any other bearer value is still treated as an APP key.
- Adapt the status page change update to go-flashduty's pointer fields.
Pick up NewClientWithAccessToken, used for OAuth access tokens on the HTTP
transport.
go-version: stable now resolves to a Go release newer than the one
golangci-lint v2.11 was built with, so the linter panics while loading
the standard library ("file requires newer Go version").
The build failed whenever the gha cache index pointed at a blob that no
longer existed (BlobNotFound on import). The image is a single Go binary
that builds in about a minute, so the cache is not worth that failure mode.
feat(server): accept OAuth access tokens on the HTTP transport
@ysyneu
ysyneu merged commit bd586fc into main Oct 8, 2026
13 checks passed
@ysyneu
ysyneu deleted the feat/mcp-oauth branch October 8, 2026 10:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant