Skip to content

MCP OAuth v1.x: 2026-07-28 RC spec changes #100

@heskew

Description

@heskew

Tracks the six SEPs that landed in the MCP authorization spec 2026-07-28 release candidate and represent forward work beyond v1. v1 of @harperfast/oauth MCP support (parent #86) targets the 2025-06-18 stable revision; this issue catalogues what changes when the RC promotes to stable so we don't have to re-derive the diff at that point.

Background: release-candidate blog post · draft spec.

Six SEPs at a glance

SEP Topic Impact on @harperfast/oauth Lift
2468 iss parameter on authorization responses (RFC 9207) Emit iss on success + error redirects; advertise authorization_response_iss_parameter_supported: true in AS metadata XS — additive, ~30 lines
837 OpenID Connect application_type in DCR None — already supported in Stage 1 (web/native); spec MUST is client-side None
2352 Issuer binding for clients None — client-side requirement; we're a single issuer per Harper app None
2207 Refresh token requests + offline_access Honor offline_access scope opt-in at token endpoint; SHOULD NOT advertise offline_access in PRM scopes_supported XS — small token-endpoint behavior
2350 Scope accumulation in step-up flow Depends on per-tool scopes (v1.1 in #86) Blocked on per-tool scopes
2351 .well-known discovery suffix Optional path-suffixed variant (/.well-known/oauth-protected-resource/<mcp-path>); root variant we serve is spec-compliant S — additive, multi-MCP-endpoint apps

Plus one non-SEP change worth tracking:

Item Topic Impact Lift
Registration priority order DCR is now fallback; pre-registration + Client ID Metadata Documents come first We satisfy "at least DCR" today. CIMD adds a whole new registration path — SHOULD support per the RC. Docs framing should update M — new endpoint + AS metadata field + client validation logic

Per-SEP details

SEP-2468 — iss parameter on authorization responses (RFC 9207)

RC spec text:

"MCP authorization servers SHOULD include the iss parameter in authorization responses, including error responses, as defined in RFC 9207 Section 2. Authorization servers that include the iss parameter MUST advertise this by setting authorization_response_iss_parameter_supported to true in their metadata."

"A future revision of this specification is expected to upgrade authorization server inclusion of iss from SHOULD to MUST. Implementers are encouraged to emit and validate iss now to ease that transition."

Implementation:

  • Stage 2 (src/lib/mcp/wellKnown.ts): add authorization_response_iss_parameter_supported: true to buildAuthorizationServerMetadata's return object.
  • Stage 3 (src/lib/mcp/callback.ts): in buildSuccessRedirect and buildErrorRedirect, add &iss=<configured-issuer> (use mcp.issuer, fall back to resolveIssuer(request, mcpConfig)).
  • Stage 3 error paths in src/lib/handlers.ts: in mcpErrorRedirect, also add &iss=... for consistency.

Security rationale: mitigates mix-up attacks where an attacker-controlled AS forwards an honest AS's code to the wrong token endpoint. PKCE alone doesn't prevent this because the verifier reaches the attacker. RFC 9207 §1 is the canonical reference.

Forward-compat note: the RC explicitly encourages early adoption. Emitting iss under the 2025-06-18 stable banner is strictly additive — no contradiction with the stable spec. If we want a single point in time to adopt this without a "v1.x" branch, fold it into the next stage PR.

SEP-837 — OpenID Connect application_type in DCR

RC spec text:

"MCP clients MUST specify an appropriate application_type during Dynamic Client Registration. Omitting it defaults to 'web' under OIDC, which can conflict with native-style redirect URIs."

Status: No-op for us. Stage 1 (PR #89) already accepts application_type (web/native/default web). The MUST is client-side — clients must specify it; we accept what they send. Our default of web matches the OIDC spec default the RC cites.

SEP-2352 — Issuer binding for clients

RC spec text:

"Clients that use pre-registered credentials, or persist client credentials obtained via Dynamic Client Registration, MUST associate those credentials with the specific authorization server that issued them, keyed by the authorization server's issuer identifier."

Status: No-op for us (server side). Single issuer per Harper app deployment. If a customer migrates their mcp.issuer config, clients with cached credentials need to re-register — that's their problem to detect via the RC's mechanism.

SEP-2207 — Refresh token requests

RC spec text:

"MCP Clients that desire refresh tokens... SHOULD include refresh_token in their grant_types client metadata. MAY add offline_access to the scope parameter... when the Authorization Server metadata contains it in scopes_supported."

"MCP Servers (Protected Resources) SHOULD NOT include offline_access in WWW-Authenticate scope or Protected Resource Metadata scopes_supported, as refresh tokens are not a resource requirement."

Implementation for Stage 4 (#94):

  • /oauth/mcp/token: honor refresh_token grant when registered client has refresh_token in grant_types. (Default DCR registration already includes it.)
  • Stage 2's PRM: do not advertise offline_access in scopes_supported. Currently we don't list any scopes — compliant.
  • Stage 4's AS metadata can list offline_access in scopes_supported (for clients that opt-in to refresh tokens) — but this is opt-in at the AS level, not required.

Lift: mostly already in plan; explicit offline_access non-advertisement in PRM is the only new constraint.

SEP-2350 — Scope accumulation in step-up

RC spec text:

"When re-authorizing, clients SHOULD include these scopes alongside any previously granted scopes to avoid losing permissions needed for other operations."

Status: Blocked on per-tool scopes, which is v1.1 of #86 (resolved decisions, item 2: "Token scoping → role-level, matching human OAuth. Per-tool scoping deferred to v1.1"). When per-tool scopes land, step-up + scope accumulation comes with it.

SEP-2351 — .well-known discovery suffix

RC spec text:

"Well-Known URI: Serve metadata at a well-known URI as specified in RFC9728. This can be either:

  • At the path of the server's MCP endpoint: https://example.com/public/mcp could host metadata at https://example.com/.well-known/oauth-protected-resource/public/mcp
  • At the root: https://example.com/.well-known/oauth-protected-resource"

Status: Stage 2 serves the root variant — spec-compliant. The path-suffixed variant is additive — enables Harper apps that host multiple /mcp endpoints under different paths (e.g. /team-a/mcp, /team-b/mcp) to differentiate metadata. Not relevant for the single-/mcp-per-app shape we target in v1.

Implementation when needed: route /.well-known/oauth-protected-resource/* through the same handler, with the trailing path used to scope the canonical resource URI.

Bonus — Client ID Metadata Documents (not a SEP, but new in RC)

RC spec text:

"Clients supporting all options SHOULD follow the following priority order:

  1. Use pre-registered client information
  2. Use Client ID Metadata Documents if the Authorization Server indicates it supports them (via client_id_metadata_document_supported in OAuth Authorization Server Metadata)
  3. Use Dynamic Client Registration as a fallback"

DCR is demoted to fallback. CIMD lets MCP clients use an HTTPS URL as their client_id, where the URL resolves to a JSON document with client metadata. The AS fetches and validates the document at authorize time.

Implementation for v1.1:

  • New AS-side flow: when client_id is an HTTPS URL, fetch the metadata document, validate client_id matches URL exactly, validate redirect_uri against allowed list, cache per HTTP cache headers.
  • Add client_id_metadata_document_supported: true to AS metadata when implemented.
  • Security: SSRF protection on the AS-side fetch, localhost-redirect-impersonation warnings (per RC §"Localhost Redirect URI Risks").

Why deferred: new endpoint + new validation path + new security surface. Not blocking v1 because DCR fallback still works.

When this issue moves

This issue stays in pending until the RC promotes to stable. At that point:

  1. Verify each SEP against the final spec text (RC → stable diffs are usually small but not zero)
  2. File per-SEP sub-issues for the items with XS/S/M lift
  3. Mark v1.x done when CIMD + iss + path-suffixed well-known have shipped

If a customer asks for any specific item earlier (e.g. an enterprise wants CIMD before stable lands), we cherry-pick it ahead of the others.

Related


🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions