Repository navigation
CIMD client metadata URL must be HTTPS with no loopback exemption, so CIMD cannot be driven against a local fixture #2305
Description
The problem
getCimdClientMetadataUrlError (core/client/config-parse.ts) rejects any CIMD client metadata URL that is not HTTPS:
if (url.protocol !== "https:") {
return CIMD_METADATA_URL_HTTPS_ERROR;
}There is no loopback exemption. The check is applied to the settings form and, through refineCimdMetadataUrl → CimdConfigSchema, to client.json as it comes off disk — so it cannot be worked around by hand-editing the file either.
The consequence is that CIMD cannot be exercised against anything served locally. Every test server in this repo speaks plain HTTP, so a CIMD metadata document hosted by one of them is not a legal clientMetadataUrl, and the whole registration path is unreachable in local development.
Why this is worth fixing rather than documenting
This is the same shape as #2280 / #1944, from the other side. There, the SDK's over-narrow loopback allow-list for token endpoints made a legitimate local setup fail, and we treated it as a real defect worth explaining carefully. This is our own over-narrow allow-list doing the same thing to our own testing story.
Concretely, it is why #2242 shipped verified by unit and integration tests alone: the v2.6.0 release smoke recorded it as the one row with an observable UI surface that could not be reached. Driving it required standing up a self-signed HTTPS listener purely to hold a JSON document, plus NODE_TLS_REJECT_UNAUTHORIZED=0 in the test server's environment so its own fetch of that document would succeed. That worked — Connection Info read Client registration — Client ID Metadata (CIMD) with the client id equal to the metadata URL — but it is not a reproduction anyone will run casually.
The security question, stated honestly
The HTTPS requirement is not arbitrary: a CIMD client id is a URL an authorization server dereferences, and over plain HTTP its contents are attacker-modifiable in transit. SEP-991 is right to expect HTTPS in production.
But loopback is the documented exception to exactly this reasoning everywhere else in the stack — it is why the SDK exempts localhost, 127.0.0.1 and ::1 from its own token-endpoint TLS assertion, and why core/auth/cimd.ts already says in a comment that an already-stored client_id may be an http:// URL "used by local dev/test metadata servers". So the runtime is willing to use one; only the config validation refuses to accept one.
Options
- Exempt the three loopback literals, matching the SDK's token-endpoint exemption and this repo's own comment. Narrowest change, and consistent with what the runtime already tolerates.
- Keep the check and add optional TLS to the composable test server, so a fixture can serve the document over HTTPS with a self-signed cert. Heavier, and pushes a cert into the repo or a generation step into the harness.
- Gate the exemption behind an explicit dev flag.
Option 1 is the one that matches existing precedent; recording the others because the trade is a real one and the security reasoning above deserves a decision rather than a default.
Acceptance
- A loopback
http://CIMD metadata URL is accepted (whatever mechanism is chosen), or a decision is recorded against this issue explaining why it should not be -
test-servers/configs/oauth-cimd-http.jsoncan be driven end to end from the web client with no self-signed HTTPS listener - The non-loopback HTTPS requirement is unchanged, with a test asserting a plain
http://public host is still rejected -
docs/test-servers.md's CIMD section updated to drop the workaround
Context
Found while building the CIMD fixture during the v2.6.0 release smoke, to clear the one finding the ledger recorded as unreachable.
Activity
test: pin the CIMD form copy; narrow the "no exemption" claim in the …
cliffhall commentedon Sep 11, 2026
Shipped in #2326, merged to
v2/mainas336e04521.Resolved as option 1 from the issue: a plain
http:CIMD metadata URL is accepted on the three literals the SDK itself exempts from its token-endpoint TLS assertion —localhost,127.0.0.1and[::1].Acceptance:
http://CIMD metadata URL is accepted, in the settings form and inclient.jsonon disk.test-servers/configs/oauth-cimd-http.jsondrives end to end from the web client with no self-signed HTTPS listener — verified against the live fixture, with Connection Info readingClient registration — Client ID Metadata (CIMD)and the client id equal to the metadata URL.http://public host is still rejected —localhost.andtenant.app.localhostincluded, so this allow-list and the SDK's cannot disagree about one URL.docs/test-servers.md's CIMD section drops the workaround;specification/v2_auth_smoke_testing.mdno longer calls the exemption test-only.One correction the review surfaced, worth recording here: the exemption compares the WHATWG-canonicalized
URL.hostname, so it covers alternate spellings of those three addresses (127.1,2130706433,[0:0:0:0:0:0:0:1],127.0.0.1.) rather than three input strings. That is exactly what the SDK does — measured againstassertSecureTokenEndpoint, which accepts all four and refuses the same near-misses.Closing by hand — closing keywords do not fire for PRs targeting
v2/main.feat(test-servers): a CIMD showcase fixture that serves its own clien…
fix: exempt loopback hosts from the CIMD metadata URL HTTPS requirement