Make auth work from a Capacitor WebView origin (JWT-only, CORS/CSRF for capacitor://localhost) #22

Closed
opened 2026-07-26 04:54:15 -07:00 by westfarn · 0 comments
Owner

Risk

Blocks #20 (Android) and #21 (iOS).

Today llm-fe/src/axiosApi.js authenticates with a JWT plus a CSRF cookie read via js-cookie. In a browser the app and API are same-site-ish (chat.aimloperations.com -> chatbackend.aimloperations.com), so the cookie flow works. Inside Capacitor the page origin is https://localhost (Android) or capacitor://localhost (iOS), which is cross-site relative to the backend domain, and WKWebView blocks third-party cookies by default. Result: the CSRF cookie is never readable, POSTs get rejected, and login fails on device even though the same bundle works in a browser.

Work

  • Audit src/axiosApi.js and the auth context for every request that depends on a cookie (CSRF token, session, refresh token).
  • Move the native path to header-only auth: Authorization bearer JWT, refresh token in Capacitor Preferences / secure storage rather than a cookie.
  • Confirm whether Django CSRF enforcement can be skipped for JWT-authenticated API endpoints, or supply the CSRF token via a header fetched from an endpoint instead of a cookie.
  • chat_backend changes: add https://localhost and capacitor://localhost to CORS_ALLOWED_ORIGINS and CSRF_TRUSTED_ORIGINS; verify preflight (OPTIONS) responses and Access-Control-Allow-Credentials behavior.
  • Decide on a single strategy that works for web + Android + iOS so we do not fork the auth code per platform.
  • Verify on device: login, token refresh after expiry, logout, password reset, 401 handling.

Done when

Login, refresh, and an authenticated API call all succeed from a Capacitor build on both platforms, with no cookie dependency, and the browser build still works unchanged.

## Risk Blocks #20 (Android) and #21 (iOS). Today `llm-fe/src/axiosApi.js` authenticates with a JWT plus a CSRF cookie read via `js-cookie`. In a browser the app and API are same-site-ish (`chat.aimloperations.com` -> `chatbackend.aimloperations.com`), so the cookie flow works. Inside Capacitor the page origin is `https://localhost` (Android) or `capacitor://localhost` (iOS), which is cross-site relative to the backend domain, and WKWebView blocks third-party cookies by default. Result: the CSRF cookie is never readable, POSTs get rejected, and login fails on device even though the same bundle works in a browser. ## Work - [ ] Audit `src/axiosApi.js` and the auth context for every request that depends on a cookie (CSRF token, session, refresh token). - [ ] Move the native path to header-only auth: `Authorization` bearer JWT, refresh token in Capacitor Preferences / secure storage rather than a cookie. - [ ] Confirm whether Django CSRF enforcement can be skipped for JWT-authenticated API endpoints, or supply the CSRF token via a header fetched from an endpoint instead of a cookie. - [ ] `chat_backend` changes: add `https://localhost` and `capacitor://localhost` to `CORS_ALLOWED_ORIGINS` and `CSRF_TRUSTED_ORIGINS`; verify preflight (`OPTIONS`) responses and `Access-Control-Allow-Credentials` behavior. - [ ] Decide on a single strategy that works for web + Android + iOS so we do not fork the auth code per platform. - [ ] Verify on device: login, token refresh after expiry, logout, password reset, 401 handling. ## Done when Login, refresh, and an authenticated API call all succeed from a Capacitor build on both platforms, with no cookie dependency, and the browser build still works unchanged.
westfarn added a new dependency 2026-07-26 04:55:27 -07:00
westfarn added a new dependency 2026-07-26 04:55:28 -07:00
westfarn referenced this issue from a commit 2026-08-03 12:12:40 -07:00
westfarn referenced this issue from a commit 2026-08-03 12:14:00 -07:00
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Reference: ai_ml_operations/chat_web_app#22