You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
fix(client): don't follow cross-origin redirects with a bearer token #177
In bearer transport (React Native), authorizedFetch and the client's calls under the adapter mount send the access token in Authorization. fetch follows redirects by default. If the application's API, or a misconfigured proxy in front of it, answers with a redirect to another origin, the request is sent on, and whether Authorization goes with it depends on the platform's networking stack:
Node 24's fetch (undici) and current Chrome, Firefox and Safari drop Authorization and Cookie on a cross-origin redirect, per the Fetch standard. That was tested against a local 302. x-seamless-auth-transport is kept.
OkHttp (Android) drops auth headers when the host changes.
iOS NSURLSession, which React Native's fetch uses on iOS, is unverified. It may carry custom headers across a redirect.
The #175 origin check judges only the URL the request starts at, not where a redirect takes it.
Proposed
In bearer transport, don't follow a redirect to an origin outside apiHost and trustedOrigins:
Default redirect: 'manual' or 'error' for bearer authorizedFetch and the adapter calls, unless the caller sets redirect explicitly. Then surface a clear error.
Or, as a fallback where the platform ignores redirect, reject when response.redirected and new URL(response.url).origin is not trusted. That detects the redirect after the fact but does not prevent the send.
Done when
The iOS behaviour is verified on a device or simulator with a test server that answers 302 to another origin.
Bearer requests never reach an untrusted origin with the access token, on iOS and Android.
There's a test in packages/client/tests/transport.node.test.ts, with the README updated.
Verified on iOS (2026-10-20): iPhone 17 Pro simulator, iOS 26.5, Expo Go SDK 57, React Native 0.86.3, @seamless-auth/client 0.7.0 (with #192). A probe app ran against two local servers: localhost:5700 answering 302 to 127.0.0.1:5701, and the other origin logging every Authorization it received.
Check
Result
Raw fetch with Authorization, cross-origin 302
Followed to 127.0.0.1:5701; the other origin received noAuthorization. NSURLSession strips it on a cross-origin hop here
Raw fetch, redirect: 'manual'
Honoured: status 302 returned, not followed
Client bearer authorizedFetch, cross-origin 302
Rejected with UntrustedRedirectError; the other origin received no request at all
Client bearer authorizedFetch, same-origin 302
Followed; the landing route received Bearer client-token
So on this iOS and React Native version the token cannot reach another origin through a redirect, whether or not the client intervenes, and the client refuses the hop before sending anything.
One gap found: on React Native a followed redirect reports response.redirected === false while response.url is the new origin. The client's after-the-fact check keys on redirected, so it would miss a redirect on a platform that ignores redirect: 'manual'. React Native 0.86 honours manual, so it does not bite here, but the check should compare response.url with the requested URL instead. Not yet verified: Android (OkHttp is documented to drop auth headers on a host change) and older React Native versions.
Closing: fixed in #192 (client 0.7.0) and verified on iOS 26.5 / React Native 0.86.3 in the comment above. The after-the-fact check gap found there is tracked separately.
Activity
fix(client): don't follow cross-origin redirects with a bearer token (#…
Bccorb commentedon Oct 20, 2026
Verified on iOS (2026-10-20): iPhone 17 Pro simulator, iOS 26.5, Expo Go SDK 57, React Native 0.86.3,
@seamless-auth/client0.7.0 (with #192). A probe app ran against two local servers:localhost:5700answering 302 to127.0.0.1:5701, and the other origin logging everyAuthorizationit received.fetchwithAuthorization, cross-origin 302127.0.0.1:5701; the other origin received noAuthorization. NSURLSession strips it on a cross-origin hop herefetch,redirect: 'manual'authorizedFetch, cross-origin 302UntrustedRedirectError; the other origin received no request at allauthorizedFetch, same-origin 302Bearer client-tokenSo on this iOS and React Native version the token cannot reach another origin through a redirect, whether or not the client intervenes, and the client refuses the hop before sending anything.
One gap found: on React Native a followed redirect reports
response.redirected === falsewhileresponse.urlis the new origin. The client's after-the-fact check keys onredirected, so it would miss a redirect on a platform that ignoresredirect: 'manual'. React Native 0.86 honoursmanual, so it does not bite here, but the check should compareresponse.urlwith the requested URL instead. Not yet verified: Android (OkHttp is documented to drop auth headers on a host change) and older React Native versions.Bccorb commentedon Oct 20, 2026
Closing: fixed in #192 (client 0.7.0) and verified on iOS 26.5 / React Native 0.86.3 in the comment above. The after-the-fact check gap found there is tracked separately.