Repository navigation
fix(native): send iOS native-mode auth requests through NSURLSession - #475
Conversation
The API admits a native auth request (`x-auth-mode: native`) only without `Origin`, `Sec-Fetch-Mode` and cookies, and WebKit puts the first two on every fetch from the page and its worker, so sign-in on a device got 403 from `/auth/browser-login/initiate`. The iOS worker now hands those requests to the host, which sends them with an ephemeral, cookieless NSURLSession and posts the response back through the page. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Maple review🔴 Confidence 4/10 · risky as written. The host transport follows redirects the auth client explicitly forbids, and nothing tests the new routing; that security gap decides the number. Fixes iOS native-mode sign-in by sending those requests through the host's
Before merge
Findings🟠 Warning · F1 · Host path follows redirects the auth client forbids (
|
|
Caution Review failedThe pull request is closed.
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. |
|
Merged with 1 step from "Before merge" still open. If it is done, tick it on the review comment; if not, now is the time.
|
| reject(outgoing.signal.reason) | ||
| }) | ||
| const headers = Object.fromEntries(outgoing.headers) | ||
| request({ fetch: JSON.stringify({ id, url: outgoing.url, method: outgoing.method, headers, body }) }) |
There was a problem hiding this comment.
Warning
Host path follows redirects the auth client forbids (redirect: "error")
F1 · Warning · security
The auth runtime builds its client with redirect: "error" because the session travels in x-auth-request-session headers (apps/web-foldkit/src/platform/desktop-auth.ts:159). The payload sent to the host carries no redirect, and NSURLSession follows a redirect by default, so a 3xx re-sends those credential headers to the Location origin and the caller gets that response instead of a rejection.
Put `redirect: outgoing.redirect` in the payload, and have `http.rs` refuse the redirect (a task delegate answering `None`) so a 3xx surfaces as the load failure the client asked for.
🤖 Prompt to fix with an AI agent
In `apps/native/src/ios.ts:72`: Host path follows redirects the auth client forbids (`redirect: "error"`).
The auth runtime builds its client with `redirect: "error"` because the session travels in `x-auth-request-session` headers (`apps/web-foldkit/src/platform/desktop-auth.ts:159`). The payload sent to the host carries no `redirect`, and `NSURLSession` follows a redirect by default, so a 3xx re-sends those credential headers to the `Location` origin and the caller gets that response instead of a rejection.
Suggested fix: Put `redirect: outgoing.redirect` in the payload, and have `http.rs` refuse the redirect (a task delegate answering `None`) so a 3xx surfaces as the load failure the client asked for.
Verify the problem exists at that location before changing it, and keep the fix to those lines.
| let nextFetch = 0 | ||
| globalThis.fetch = async (input: RequestInfo | URL, init?: RequestInit) => { | ||
| const outgoing = new Request(input, init) | ||
| if (outgoing.headers.get(nativeHeaders.modeHeader) !== "native") return webFetch(outgoing) |
There was a problem hiding this comment.
Warning
New fetch routing and reply handling are covered by no test
F2 · Warning · tests
apps/native/src tests its other global shims (shims.test.ts, and data-source.ts through offline-backend.test.ts), but nothing exercises this branch: a native request reaching the host, its id matching a late reply, a non-native request on WebKit's fetch, or { error } becoming a TypeError. The change's whole behavior is unverified in CI.
Extract the routing into `src/native-fetch.ts` taking the web fetch, `request` and a reply source, and test it: native routed, others passed through, an error reply throws.
🤖 Prompt to fix with an AI agent
In `apps/native/src/ios.ts:62-63`: New `fetch` routing and reply handling are covered by no test.
`apps/native/src` tests its other global shims (`shims.test.ts`, and `data-source.ts` through `offline-backend.test.ts`), but nothing exercises this branch: a native request reaching the host, its `id` matching a late reply, a non-native request on WebKit's fetch, or `{ error }` becoming a `TypeError`. The change's whole behavior is unverified in CI.
Suggested fix: Extract the routing into `src/native-fetch.ts` taking the web fetch, `request` and a reply source, and test it: native routed, others passed through, an error reply throws.
Verify the problem exists at that location before changing it, and keep the fix to those lines.
Coverage Report
File CoverageNo changed files found. |
Follow-up to #474, which merged before this commit was pushed.
Problem
Sign-in on a real iPhone (TestFlight build 2968) failed with "Something went wrong". Production traces show
POST /auth/browser-login/initiateanswering 403. The auth transport admits a native request (x-auth-mode: native) only withoutOrigin,Sec-Fetch-Modeand cookies (@yielded/authhttp-operation/security.ts), and WebKit stampsOrigin/Sec-Fetch-Modeon every fetch from the hidden page and its worker; no script can remove them. The simulator never hit this because sign-in there ran against a local stand-in.Confirmed against production: the same native initiate request returns 400 (admitted, empty test body) without
Originand 403 withOrigin: https://app.hazel.sh.Fix
src/ios.ts: the worker'sfetchhands anyx-auth-mode: nativerequest to the host as{ fetch }and builds aResponsefrom the host's reply; everything else stays on WebKit's fetch.host/ios/src/http.rs: sends it with an ephemeral, cookielessNSURLSession(noOrigin, noSec-Fetch-*) and posts{ id, status, headers, body }or{ id, error }back.bridge.rs/page.rs: thefetchrequest and the__hazel.replypath from host to worker.Verification
cargo check+clippyforaarch64-apple-iosclean;cargo test -p hazel-iosand the native vitest suite pass.🤖 Generated with Claude Code
Open in [code]smith · Need help on this PR? Tag
@codesmith-botwith what you need.