Repository navigation
Conversation
II's frontend is a public https origin that fetches the #4091 allow-list from http://127.0.0.1:<port>. Chrome classifies that as a private-network request and preflights it with Access-Control-Request-Private-Network, blocking the fetch unless the response grants it. The listener registered GET/POST only, so preflights got 405 and II could never read the allow-list: every real browser sign-in failed with "This connection link is missing information or has been changed", while curl and the e2e harness — neither of which preflights — saw a healthy 200. All three routes now answer OPTIONS with the private-network grant (tab navigation into /callback is preflighted too, not just the allow-list fetch), and a raw-socket test asserts it, since only a preflight reproduces the failure. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AqNkpMQiQHzYxC2djTfvBK
There was a problem hiding this comment.
Pull request overview
Adds Private Network Access preflight support to the transient loopback login listener, enabling production Internet Identity browser sign-in.
Changes:
- Handles
OPTIONSacross all login routes with required CORS/PNA headers. - Adds a raw-socket regression test for allow-list and callback preflights.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
crates/imcp2-local/src/login/routes.rs |
Implements PNA preflight responses. |
crates/imcp2-local/src/login/tests.rs |
Tests browser-style private-network preflights. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
aterga
marked this pull request as ready for review
August 27, 2026 20:32
Collaborator
|
The PNA (Private Network Access) standard was abandoned and superseded by LNA (Local Network Access) standard, this is only relevant for non top-level requests (e.g. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The login listener answers a browser's CORS/Private-Network-Access preflight with 405, because its three routes are registered for
GET/POSTonly. When a public https origin fetches into loopback, Chrome preflights withAccess-Control-Request-Private-Network: truefirst and blocks the fetch unless the response grants it, so the#4091allow-list is unreadable from a browser whilecurland the e2e harness — neither of which preflights — see a healthy200.Scope correction (important). I originally opened this believing it explained why
imcp2-local's sign-in fails against production Internet Identity with "Invalid request — this connection link is missing information or has been changed". It does not. Instrumenting II's own deployed bundle shows our link parses successfully (itsregistration_key/callback/state/ttlschema accepts it, loopbackhttp://callback included), and in both a real browser and a headless replay no request to127.0.0.1is ever attempted — so the preflight is never reached. That failure is still open and is II-side; notes below.This PR is therefore a latent-correctness fix, not a user-visible one: it is necessary for the allow-list fetch to work in any environment where it is attempted (a dev-CSP II deployment, a local replica), and it is not sufficient for production sign-in.
Related issues
Found while testing the local binary end to end on macOS after #152.
Changes
OPTIONSwithAccess-Control-Allow-Private-Network: trueplus the accompanying CORS headers. Chrome enforces PNA for the tab navigation into/callbackas well as the allow-list fetch, so the preflight is registered on every route.Testing
cargo build --locked --all-targetscargo test --locked --all-targets— 240 tests green (21 inimcp2-local, including the new preflight test)cargo fmt --all/cargo clippy --all-targets— no warnings in the changed files (remainingmap_orwarnings are pre-existing inimcp2-core)--features e2e):local_login_end_to_endpassesNotes for the still-open production failure
Evidence gathered against the live
id.aibundle, recorded here so it isn't lost:connect-src 'self' https:— afetch()tohttp://127.0.0.1:<port>is not permitted at all, which is consistent with no loopback request being issued. The same policy carriesform-action 'self' http://127.0.0.1:*, so loopback form submission is explicitly allowed while loopback fetch is not.dev_cspbuild flag (its secure-context predicate acceptshttp:on loopback only when that flag is set), suggesting loopback callbacks are enabled for development deployments rather than production.🤖 Generated with Claude Code
https://claude.ai/code/session_01AqNkpMQiQHzYxC2djTfvBK