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.
This pull adds a test only, because `GET /.well-known/oauth-protected-resource` was already on `main` and already met the issue's route requirements. The route is in `src/http/oauth.ts`, it returns RFC 9728 JSON, and `src/core/reserved.ts` was already complete.
shipped production is serving it deploy d5b2fe2
This pull adds a test only, because GET /.well-known/oauth-protected-resource was already on main and already met the issue's route requirements. The route is in src/http/oauth.ts, it returns RFC 9728 JSON, and src/core/reserved.ts was already complete.
The new test/oauth-protected-resource.test.ts boots the app with url: "https://forge.example" and requests the route with spoofed x-forwarded-host and x-forwarded-proto headers. It asserts that:
resourceishttps://forge.example/mcp.authorization_serversis["https://forge.example"].bearer_methods_supportedis["header"].
The origin comes from the configured URL through publicUrl, not from the request headers. Before this, no test covered bearer_methods_supported or the header-spoofing case.
- GATE:
scripts/gate.tsnow derives the gate fromtest/*.test.tsinstead of aGATElist, so the new file is in it automatically. - Tests: the new test,
test/oauth-discovery.test.tsandtest/reserved-names.test.tspass together (34 tests). I did not run the full check. - Not done: I changed no route code and added no dependency.
The document also advertises scopes_supported: ["ro","rw"], an extra field that RFC 9728 allows and the existing discovery test already checks.
Clean. This pull adds a test and nothing else. The route already on main (src/http/oauth.ts:135) builds resource and authorization_servers from ctx.url.origin, which publicUrl rebuilds from the configured FORGE_URL without reading any forwarded header. The new test pins exactly that: it sends a spoofed x-forwarded-host/x-forwarded-proto and still gets https://forge.example/mcp. If someone later lets publicUrl trust those headers, this test fails. It also covers bearer_methods_supported, which nothing tested before. I ran it at this head and it passes (1 pass, 5 expects).
On security, there is no new input, no write and no new door. The route is a public, read-only discovery document, so the terminal has nothing to match. The test follows test/oauth-discovery.test.ts and cleans up its data dir and app.
Not verified: my sandbox could not reach the preview host, and it cannot read the screenshots under /data/looks. The judgement above comes from the code and the local run only.
This pull adds a test only, because
GET /.well-known/oauth-protected-resourcewas already onmainand already met the issue's route requirements. The route is insrc/http/oauth.ts, it returns RFC 9728 JSON, andsrc/core/reserved.tswas already complete.The new
test/oauth-protected-resource.test.tsboots the app withurl: "https://forge.example"and requests the route with spoofedx-forwarded-hostandx-forwarded-protoheaders. It asserts that:resourceishttps://forge.example/mcp.authorization_serversis["https://forge.example"].bearer_methods_supportedis["header"].The origin comes from the configured URL through
publicUrl, not from the request headers. Before this, no test coveredbearer_methods_supportedor the header-spoofing case.scripts/gate.tsnow derives the gate fromtest/*.test.tsinstead of aGATElist, so the new file is in it automatically.test/oauth-discovery.test.tsandtest/reserved-names.test.tspass together (34 tests). I did not run the full check.The document also advertises
scopes_supported: ["ro","rw"], an extra field that RFC 9728 allows and the existing discovery test already checks.Closes #2391