Skip to content

v1.0.8 - #47

Merged
Vauth merged 11 commits into
mainfrom
fix-login-406
Oct 30, 2026
Merged

Vauth merged 11 commits into
mainfrom
fix-login-406

Conversation

@Vauth

@Vauth Vauth commented Oct 30, 2026

Copy link
Copy Markdown
Owner

What's New in v1.0.8

  • New Browser Sign-In (HTTP 406 Fix): Replaced email and password login with official in-app browser sign-in. Direct API requests were being blocked by Mozilla's bot protection (HTTP 406); signing in via the official Firefox web page resolves this completely and supports all 2FA/OTP methods seamlessly. Fix HTTP 406 on login: browser-based PKCE sign-in #46

Vauth and others added 10 commits October 29, 2026 16:43
Mozilla's Fastly bot protection blocks direct FxA password login
POSTs with HTTP 406 (empty body), which no API-side fix can bypass.

This mirrors the official Mozilla VPN client login flow:
- New BrowserLoginScreen: in-app WebView opens the Guardian login URL
  (vpn.mozilla.org/api/v2/vpn/login/android) which redirects to
  accounts.firefox.com; the real browser engine passes the Fastly
  challenge automatically.
- PKCE (S256) code pair; completion redirect to /oauth/success is
  intercepted and the code is exchanged via /api/v2/vpn/login/verify
  for a Guardian JWT session.
- FastlyChallengeSolver rewritten: replays the actually-served
  challenge body, ignores HTTP status, solves pow/pat/clientmetrics.
- GuardianClient: same body-aware 406 challenge handling.
- LoginScreen: 'Sign in with browser' as the recommended primary
  button; legacy email/password login kept as a fallback with a
  friendly error when Fastly blocks it.
Guardian's /api/v2/vpn/login/android returns JSON (not a redirect) and
sets a flow session cookie. The official client performs this GET with
its own HTTP stack and later presents the same session when POSTing to
/api/v2/vpn/login/verify. Previously the WebView performed the start
request, so the flow session lived in the WebView cookie store while
the verify call went out from the app's OkHttp client without it —
Guardian could not match the authorization code against the PKCE
challenge and returned errno 129 "'code' not found or expired".

Now startBrowserLoginFlow() performs the start GET via the shared
ControlPlaneHttp client (cookie jar keeps the flow session, Fastly 406
challenge handling included) and builds the accounts.firefox.com
authorization URL from the returned fxa_oauth JSON, exactly like the
official client. The WebView only handles the accounts.firefox.com
sign-in and the completion redirect is still intercepted locally.
…w cookie

Guardian registers the authorization code server-side only when the
browser actually GETs https://vpn.mozilla.org/oauth/success?code=...
(the FxA completion redirect). The previous build blocked that
navigation inside shouldOverrideUrlLoading, so the code was never
registered and POST /api/v2/vpn/login/verify always failed with
401 errno 129 "'code' not found or expired" (reproduced against the
live Guardian API with a probe request).

- The WebView now only blocks the mozilla-vpn:// deep link; every https
  navigation - including the completion redirect - is allowed through,
  and the code is reported from doUpdateVisitedHistory, i.e. after
  Guardian answered the completion GET.
- The flow session cookie issued on the /login/android start GET is
  copied from the shared OkHttp cookie jar into the WebView cookie
  store before the sign-in page loads, and mirrored back into the jar
  right before /login/verify (Guardian may rotate the session while
  serving the success page).
- User-Agent aligned with the official Android client (sys:android
  instead of sys:linux).
- versionCode 45 / versionName 1.0.10
…ebChannel

The /api/v1/fpn/* proxy endpoints only accept an FxA OAuth access token
(the grant the reference client uses), but the previous browser flow
stored a Guardian JWT from /api/v2/vpn/login/verify — so Guardian answered
401 on both /fpn/token and /fpn/activate.

- browser sign-in now opens the accounts.firefox.com sync flow and captures
  the account session token from the fxaccounts:login WebChannel message
  (the WebView answers fxa_status and can_link_account like Firefox does)
- the app mints the FxA OAuth token locally with the fxa-credentials grant,
  storing access + refresh tokens
- token refresh moved to the dedicated OAuth token server
  (oauth.accounts.firefox.com); the auth server answers errno 110 for the
  refresh grant
- mintProxyPass now renews the token BEFORE activating the entitlement and
  fails fast with 'sign in again' once the session is truly dead
- sessions holding the retired Guardian JWT are cleared on restore
- CI now builds on every branch push
@Vauth Vauth linked an issue Oct 30, 2026 that may be closed by this pull request
@Vauth
Vauth merged commit 7501192 into main Oct 30, 2026
2 checks passed
@Vauth
Vauth deleted the fix-login-406 branch October 30, 2026 11:47
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.

Login problem

2 participants