Skip to content

fix(jmap): request /jmap/session directly to survive iOS auth-drop on redirect - #39

Open
koolninad wants to merge 1 commit into
bulwarkmail:mainfrom
koolninad:fix/jmap-session-ios-auth-drop
Open

fix(jmap): request /jmap/session directly to survive iOS auth-drop on redirect#39
koolninad wants to merge 1 commit into
bulwarkmail:mainfrom
koolninad:fix/jmap-session-ios-auth-drop

Conversation

@koolninad

Copy link
Copy Markdown
Contributor

Sign-in from the iOS build against a Stalwart server fails with "No account found in JMAP session".

Cause

fetchSession requests /.well-known/jmap. Stalwart answers that with a 307 to /jmap/session, and iOS NSURLSession drops the Authorization header when it auto-follows the redirect. The app therefore receives an unauthenticated session — HTTP 200 with empty accounts — and resolveAccountId throws at the end of the chain.

Browsers preserve the auth header across same-origin redirects, so the webmail never sees this. It only affects the native app on iOS, which matters now that there's an iOS TestFlight pipeline.

Fix

  • Request /jmap/session directly so the header stays attached, falling back to /.well-known/jmap on a 404 for servers that don't expose the Stalwart path.
  • Treat a 200 with no accounts as an auth failure. Stalwart responds that way to missing/invalid credentials rather than sending a 401, so a wrong password currently surfaces as "No account found in JMAP session" instead of "Invalid credentials".

Testing

vitest run src/api/__tests__/jmap-client.test.ts — 20 pass, including the two updated expectations. Full suite passes; src/stores/__tests__/auth-store.test.ts fails to parse on main already and is unrelated to this branch.

This has been running in a downstream fork against Stalwart on both platforms since early July.

🤖 Generated with Claude Code

… redirect

Signing in from the iOS build against a Stalwart server fails with "No
account found in JMAP session".

Stalwart's discovery endpoint /.well-known/jmap answers with a 307 to
/jmap/session. iOS NSURLSession strips the Authorization header when it
auto-follows that redirect, so the app gets an unauthenticated session
back — HTTP 200, empty accounts — and resolveAccountId throws. Browsers
keep the auth header on same-origin redirects, which is why the webmail
never saw this; it only bites the native app on iOS.

Request /jmap/session directly so the header stays attached, falling
back to /.well-known/jmap on 404 for servers that don't expose the
Stalwart path.

Also treat a 200 with no accounts as an auth failure. Stalwart answers
that way for missing or invalid credentials instead of sending a 401, so
a user who fat-fingers their password currently gets "No account found
in JMAP session" rather than "Invalid credentials".

Tests updated for both behaviours; full suite passes (the pre-existing
auth-store.test.ts parse failure on main is unrelated).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant