# Auth Flow Refactor: Invisible Token Exchange > Research note for future implementation ## Problem The `/callback?code=...` URL is visible in the browser during token refresh. This happens every time tokens need refreshing, not just on initial login. The current implementation appears to re-run the full OIDC redirect flow (`prompt=none`) instead of using the refresh_token. ## Current Behavior ``` Token expires → Redirect to Authentik (prompt=none) → Redirect to /callback?code=xxx → Exchange code → Continue ``` User sees URL flicker to `/callback` repeatedly. ## Desired Behavior ``` Token expires → Show overlay (lock/lightning icon) → XHR refresh request → Hide overlay → Continue ``` No URL changes. No redirects. Just a brief visual indicator. ## Key Insight **Only the initial authorization MUST redirect** (user needs to see Authentik login UI). Everything else can be XHR: | Operation | Current | Should Be | |-----------|---------|-----------| | Initial login | Redirect | Redirect (unavoidable) | | Token exchange (code → tokens) | Redirect to /callback | XHR POST | | Token refresh | Full OIDC with prompt=none | XHR POST with refresh_token | | Session expired | Redirect | Redirect (unavoidable) | ## Token Refresh via XHR ```dart final response = await dio.post( 'https://authentik.schweitz.net/application/o/token/', data: { 'grant_type': 'refresh_token', 'refresh_token': storedRefreshToken, 'client_id': clientId, }, options: Options( contentType: Headers.formUrlEncodedContentType, ), ); // Returns new access_token, refresh_token, expires_in ``` ## Potential Blocker: CORS Authentik's token endpoint may block browser XHR. Solutions: 1. **Configure Authentik CORS** - Allow `home.schweitz.net` origin 2. **Proxy through core-api** (recommended) - Flutter → `POST /auth/refresh` → core-api → Authentik - Keeps client_secret server-side - No CORS issues ## Implementation Steps 1. [ ] Verify Authentik is issuing refresh_tokens (check token response) 2. [ ] Check if refresh_token is being stored (SharedPreferences) 3. [ ] Test XHR to token endpoint (check CORS) 4. [ ] If CORS blocked, add `/auth/refresh` endpoint to core-api 5. [ ] Refactor `AuthProvider` to use XHR refresh instead of full OIDC flow 6. [ ] Add refresh overlay UI (lock icon + brief animation) 7. [ ] Remove `prompt=none` redirect logic for refresh cases ## Files to Investigate - `lib/core/auth/auth_provider.dart` - Main auth state management - `lib/core/auth/oidc_service_web.dart` - OIDC implementation - `lib/core/api/api_interceptors.dart` - Token refresh trigger point ## References - CHANGELOG entries v1.1.3-v1.1.6 document the current auth architecture - AuthController runs in `main()` before `runApp()` (v1.1.6 pattern)