Two separate discovery footguns, both found while debugging an Authentik "Redirect URI Error" on a claude.ai custom connector. RFC 9728 §3.1 puts the metadata for a resource identified by `https://host/api/mcp` at `/.well-known/oauth-protected-resource/api/mcp`. Only the root form was served, so clients that derive the metadata URL from the MCP endpoint URL — rather than reading `resource_metadata` off our 401 — got Next.js's HTML 404 and failed discovery with a JSON parse error. Add a `[...path]` route serving the same document with `resource` naming the suffixed identifier (§3.3 has the client compare it as an exact string, so echoing the bare origin would be rejected). The document body moves to `lib/auth/resource-metadata.ts` so the two routes cannot drift apart on `scopes_supported` — a divergence there costs you the `aud` claim or the refresh token. Paths are allowlisted rather than wildcarded so this cannot advertise resources the app does not serve. `buildWwwAuthenticate()` still points at the root URL; this change is purely additive. Separately, the redirect URIs an MCP provider needs depend on how clients reach it: a loopback URI for the CLI, `https://claude.ai/api/mcp/auth_callback` for a claude.ai custom connector. Registering only the former is what produces the "Redirect URI Error" page, and a portless `http://localhost/callback` entry matches nothing the CLI sends. Document both, keyed on the literal error text, and note that DCR is enterprise-gated on Authentik so these are hand-registered on a FOSS instance. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
21 lines
803 B
TypeScript
21 lines
803 B
TypeScript
import { NextResponse } from "next/server";
|
|
import { buildResourceMetadata, publicOrigin } from "@/lib/auth/resource-metadata";
|
|
|
|
export const runtime = "nodejs";
|
|
export const dynamic = "force-dynamic";
|
|
|
|
/**
|
|
* RFC 9728 — OAuth 2.0 Protected Resource Metadata.
|
|
*
|
|
* MCP clients discover the authorization server (Authentik) via this
|
|
* endpoint after receiving a 401 with `WWW-Authenticate: resource_metadata=...`.
|
|
*
|
|
* This is the root form of the document, describing the deployment origin as
|
|
* the protected resource. Clients that derive the metadata URL from the MCP
|
|
* endpoint URL instead of following the header land on the path-suffixed form
|
|
* (§3.1) served by the sibling `[...path]` route.
|
|
*/
|
|
export function GET() {
|
|
return NextResponse.json(buildResourceMetadata(publicOrigin()));
|
|
}
|