Skip to content

Feat/mcp oauth auth server#869

Draft
flipvh wants to merge 3 commits into
mainfrom
feat/mcp-oauth-auth-server
Draft

Feat/mcp oauth auth server#869
flipvh wants to merge 3 commits into
mainfrom
feat/mcp-oauth-auth-server

Conversation

@flipvh

@flipvh flipvh commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

No description provided.

flipvh and others added 3 commits July 8, 2026 22:18
…eriment 0)

Add an in-process OIDC Authorization Server (panva/node-oidc-provider)
mounted at /oauth, and switch the MCP endpoint from session-cookie auth
to OAuth bearer JWT validation. Gated behind AUTH_SERVER_ENABLED (default
off) so the template default is unchanged.

- auth-server module: node-oidc-provider bridged into Hono via the raw
  node req/res + RESPONSE_ALREADY_SENT; Authorization Code + PKCE,
  client_credentials, and resource-indicator JWT access tokens bound to
  the MCP resource (dev-only in-memory adapter / devInteractions / DCR).
- mcpAuthGuard: jose JWKS verification (issuer/audience/scope), maps the
  token subject to a Cella user and sets the context tenantGuard/orgGuard
  need; fails closed (401) on a bad/unknown subject.
- RFC 9728 protected-resource metadata + WWW-Authenticate challenge.
- MCP advertises mcpBearerAuth (HTTP bearer) instead of cookieAuth.
- whoami demo tool (flag-gated) so tools/call returns a real identity.
- 7 guard tests; MCP_PLAN.md rewritten into actionable phase checklists.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
…(phase 2+3)

Phase 3 — service identity:
- Add an McpActor concept (core/context.ts). A client_credentials token
  (sub === client_id, no user) is authorized as a service actor via an
  allowlist (MCP_SERVICE_CLIENT_IDS) plus its audience-bound tenant/org.
  The guard synthesizes a membership scoped to exactly that tenant/org so
  the shared tenantGuard/orgGuard authorize it without changes.
- whoami now reports actorType (user|service). Verified end-to-end: a
  service token flows through the full guard chain and reaches tools/call.

Phase 2 — resource-server hardening:
- Harden the remote JWKS fetch (timeout / cooldown / cacheMaxAge).
- Add root /.well-known/oauth-protected-resource alongside the
  per-tenant/org document.

Also: +2 guard tests (allowlisted service actor passes; rogue client 403).

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
…se 1)

Harden the Authorization Server so it survives restarts and drops the
dev-only shortcuts.

- Postgres storage adapter (oidc-adapter.ts): one generic oidc_payloads
  table keyed by (type, id), indexed on grant/uid/user_code/expires,
  bootstrapped with CREATE TABLE IF NOT EXISTS on the BYPASSRLS admin
  connection and wired via the provider `adapter` option. Clients, grants,
  sessions, codes and refresh/registration tokens now persist. Verified:
  a DCR client + registration token survive a fresh process.
- findAccount resolves the OIDC subject against usersTable (sub/email/name
  claims); unknown subjects fail login.
- Require a stable OIDC_PRIVATE_JWK outside development/tunnel; gate
  devInteractions, open DCR and the pre-registered dev clients to dev.

Remaining before production (tracked in MCP_PLAN.md): key rotation,
first-party consent UI, modeled OAuth tables + expiry sweeper.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
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