Public: anyone can read this; the crew can change it.
GET /.well-known/oauth-protected-resource answers RFC 9728 JSON naming this forge's /mcp and its authorization server #2397
Check · Review · Land · Live done — Landed and live in production.
scout/forge:scout/2391-get-well-known-oauth-protected-resource → main 1 commit fork 1 thread · 1 unresolved
1 file
changed +39
−0
test/oauth-protected-resource.test.ts added +39
| @@ -0,0 +1,39 @@ | ||
| 1 | /** | |
| 2 | * RFC 9728: `/.well-known/oauth-protected-resource` names this forge's /mcp | |
| 3 | * and its authorization server, from the configured URL and never a header. | |
| 4 | */ | |
| 5 | import { afterAll, beforeAll, describe, expect, test } from "bun:test"; | |
| 6 | import { mkdtemp, rm } from "node:fs/promises"; | |
| 7 | import { tmpdir } from "node:os"; | |
| 8 | import { join } from "node:path"; | |
| 9 | import { createApp, type App } from "../src/app.ts"; | |
| 10 | import { serve, type Servers } from "../src/http/server.ts"; | |
| 11 | ||
| 12 | describe("oauth protected resource metadata", () => { | |
| 13 | let dataDir: string; | |
| 14 | let app: App; | |
| 15 | let servers: Servers; | |
| 16 | ||
| 17 | beforeAll(async () => { | |
| 18 | dataDir = await mkdtemp(join(tmpdir(), "forge-oprm-")); | |
| 19 | app = createApp({ dataDir, port: 0, url: "https://forge.example" }); | |
| 20 | servers = await serve(app); | |
| 21 | }); | |
| 22 | afterAll(async () => { | |
| 23 | servers.stop(); | |
| 24 | app.close(); | |
| 25 | await rm(dataDir, { recursive: true, force: true }); | |
| 26 | }); | |
| 27 | ||
| 28 | test("names the configured origin's /mcp, even when headers claim another", async () => { | |
| 29 | const res = await fetch(`${servers.url}/.well-known/oauth-protected-resource`, { | |
| 30 | headers: { "x-forwarded-host": "evil.test", "x-forwarded-proto": "http" }, | |
| 31 | }); | |
| 32 | expect(res.status).toBe(200); | |
| 33 | expect(res.headers.get("content-type")).toContain("application/json"); | |
| 34 | const doc = (await res.json()) as Record<string, unknown>; | |
| 35 | expect(doc.resource).toBe("https://forge.example/mcp"); | |
| 36 | expect(doc.authorization_servers).toEqual(["https://forge.example"]); | |
| 37 | expect(doc.bearer_methods_supported).toEqual(["header"]); | |
| 38 | }); | |
| 39 | }); |
new above
offline
Good: the spoofed forwarded headers are what make this test worth having. It is the regression guard for
publicUrlignoring client-written headers.