Skip to content

feat(server): add AuthPlane OAuth provider - #1

Open
muralx wants to merge 1 commit into
mainfrom
feat/typescript/authplane-oauth-provider
Open

feat(server): add AuthPlane OAuth provider#1
muralx wants to merge 1 commit into
mainfrom
feat/typescript/authplane-oauth-provider

Conversation

@muralx

@muralx muralx commented Aug 5, 2026

Copy link
Copy Markdown

Language / Project Scope

Check all that apply:

  • TypeScript
  • Python
  • Documentation only
  • CI/CD or tooling

Changes

Adds oauthAuthPlaneProvider — a new OAuth provider for using
AuthPlane as an authorization server
in MCP servers. AuthPlane is an open-source, self-hosted OAuth 2.1 authorization
server for MCP. Uses DCR-direct mode: MCP clients register and authenticate
directly with AuthPlane, and the MCP server verifies AuthPlane-issued JWTs via
JWKS.

Review Readiness

  • The PR is scoped to one issue or one clearly related change
  • The PR description explains the user-visible problem and the fix
  • The diff avoids unrelated formatting, generated files, and bulk rewrites
  • I verified the affected package/docs path with the commands listed below
  • I checked for existing open PRs that already solve the same issue

Implementation Details

  1. Added src/oauth/authplane.ts with JWKS-based JWT verification, exported as
    oauthAuthPlaneProvider from mcp-use/oauth/authplane (package.json
    export and tsup.config.ts entry)
  2. Tokens are audience-bound to the resource the client requested, so there is
    no audience option to configure — verification binds to the resolved MCP
    resource
  3. Accepted signing algorithms are ES256/RS256 — the algorithms authserver
    signs access tokens with. With a remote JWKS, an unpinned verifier would
    accept whatever the matching key declares
  4. A token carrying an RFC 9449 cnf claim is rejected rather than accepted as
    a bearer credential. authserver can issue DPoP-bound tokens, mcp-use has no
    proof validation, and accepting one would drop the sender constraint the
    token was issued with
  5. AuthPlaneOAuthUser exposes the subject plus AuthPlane's delegation claims
    (agentId, agentChain, act). AuthPlane access tokens carry no OIDC
    profile claims, so there is no email/name to map; raw claims stay on
    ctx.auth.payload
  6. Added a working example at examples/auth/authplane/
  7. Amended specs/AUTH_SPEC.md and specs/AUTH_IMPLEMENTATION.md, following
    feat(server): add Better Auth OAuth provider mcp-use/mcp-use#1921 and the package's CLAUDE.md. Additions are AuthPlane-scoped
  8. No new dependencies

TypeScript Checklist

Packages Modified

  • docs
  • tests
  • cli
  • create-mcp-use-app
  • mcp-use (server)
  • mcp-use (client)
  • inspector

Pre-commit Checklist

  • Ran pnpm lint:fix to auto-fix linting issues
  • Ran pnpm format to format code with Prettier
  • Ran pnpm build and build succeeds without errors
  • Ran pnpm changeset to create a changeset (if this PR includes user-facing changes)
  • Added or updated tests if needed
  • Updated documentation in docs/ folder if needed

Example Usage (Before)

// No AuthPlane OAuth provider available

Example Usage (After)

import { MCPServer } from "mcp-use";
import { oauthAuthPlaneProvider } from "mcp-use/oauth/authplane";

const server = new MCPServer({
  name: "my-server",
  version: "1.0.0",
  oauth: oauthAuthPlaneProvider({
    issuer: process.env.AUTHPLANE_ISSUER,
    scopesSupported: ["tools:read", "tools:write"],
  }),
});

Documentation Updates

  • docs/v2/typescript/server/authentication/providers/authplane.mdx — new
    provider guide
  • docs/v2/typescript/server/authentication/index.mdx — provider table row
  • docs/docs.json — nav entry in the V2 OAuth Providers group
  • examples/auth/README.md, examples/README.md — index rows for the new
    example

Testing

  • Unit tests added to tests/oauth-direct-providers.test.ts covering metadata,
    ES256/RS256 verification, rejection of an unadvertised algorithm, rejection of
    a token minted for a different resource, rejection of a cnf-bearing token,
    delegation-claim mapping, and a missing subject
  • Compile-time contract added to tests/oauth-wiring-types.test.ts
  • Manual testing against a live authplane/authserver:latest: advertised
    metadata matches the real discovery document field for field; real tokens
    verify through a remote JWKS fetch; a token minted for a different resource is
    rejected at both the provider and HTTP layers; unauthenticated requests return
    401 with the correct resource_metadata; and a full authorization-code +
    PKCE flow completes through the mcp-use Inspector, which self-registers via DCR
  • Edge case checked with a real DPoP-bound token: rejected by this provider,
    accepted by an equivalent provider without the cnf check

Backwards Compatibility

Fully backwards compatible — new export only.

Related Issues

Proposed upstream in mcp-use#2152. This PR is internal review only; it
does not target mcp-use/mcp-use.

Add `oauthAuthPlaneProvider({ issuer })` as a direct resource-server adapter
for self-hosted AuthPlane authorization servers, exported from
`mcp-use/oauth/authplane`.

AuthPlane audience-binds every access token to the RFC 8707 resource indicator
the client requested, so the resolved canonical MCP resource is the expected
audience and no audience option is needed.

Two departures from the sibling adapters, both deliberate:

- Accepted signing algorithms are pinned to ES256 and RS256, the only two the
  authorization server issues. With a remote JWKS an unpinned verifier accepts
  whatever algorithm the matching key declares.
- A token carrying an RFC 9449 `cnf` confirmation claim is rejected rather than
  accepted as a plain bearer credential. mcp-use has no DPoP proof validation,
  so accepting one would discard the sender constraint and make an exfiltrated
  token replayable.

AuthPlane access tokens are RFC 9068 authorization tokens with no profile
claims, so the typed user exposes the subject plus the RFC 8693 delegation
chain (`act`, `agent_id`, `agent_chain`) instead of email and name.

Includes provider tests, a type-level contract, spec updates, a V2 docs page,
and a runnable example.
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