# feature:auth ## Screens - **ServerUrlScreen** -- first-run server URL entry with validation and QR scan option - **LoginScreen** -- email/password + social OAuth buttons + LDAP username mode - **RegisterScreen** -- name, username, email, password, confirm password - **ForgotPasswordScreen** -- email entry for password reset link - **TwoFactorScreen** -- 6-digit OTP input with backup code fallback ## Navigation - Sealed interface: `AuthRoute : NavKey` with typed route classes - Routes: `ServerUrl`, `Login`, `Register`, `ForgotPassword`, `TwoFactor(tempToken)`, `VerifyEmail(email)`, `ResetPassword(userId, token)`, `Terms` (all `@Serializable`) - Feature entries registered via `EntryProviderScope.authEntries()` - Flow: `ServerUrl` → `Login` → (2FA if `tempToken` returned) → `onAuthComplete` - Register and ForgotPassword are lateral routes from Login - `TwoFactor(val tempToken: String)` data class carries the nav argument directly ## OAuth Flow - `OAuthManager` opens Chrome Custom Tabs to `{serverUrl}/api/oauth/{provider}` - On return (Activity.onResume), `CookieManager.getCookie()` extracts `refreshToken=` cookie - Cookie is cleared after extraction to prevent stale reads - Supported providers configured by server: Google, GitHub, Discord, Facebook, Apple, OpenID ## Token Storage - Tokens stored in `EncryptedSharedPreferences` via `TokenDataStore` in `:core:data` - Refresh token sent as Cookie header (backend reads `cookies.parse(req.headers.cookie)`) - Access token sent as Bearer header - Token refresh is an explicit POST, not automatic cookie-based ## ViewModels - One ViewModel per screen: `ServerUrlViewModel`, `LoginViewModel`, `RegisterViewModel`, `ForgotPasswordViewModel`, `TwoFactorViewModel` - All use `AuthRepository` from `:core:data` ## Key Implementation Notes - If server URL is already stored, skip ServerUrl screen on launch - Social logins must use Custom Tabs, not WebView (cookie sharing requirement) - `openidAutoRedirect` from server config triggers automatic redirect instead of showing login form - LDAP mode: show "Username" field instead of "Email" (check server config) ### Terms Screen - `TermsScreen` + `TermsViewModel` — displays server terms, "I Accept" button - Route: `Terms` data object (part of `AuthRoute` sealed interface) in `AuthNavigation.kt` - Loads terms text via `UserRepository`, posts acceptance on confirm - `TermsViewModel.consumeAccepted()` resets navigation trigger - **Gotcha**: Terms check should happen after login if `startupConfig.requireTerms` is true - **Note**: `VerifyEmailScreen` already existed pre-Round 2 ### Localization - `strings.xml` created for all 8 modules (app, core/ui, feature/auth, chat, conversations, settings, agents, files) - Contains key toolbar titles, button labels, section headers — NOT exhaustive extraction - Full string extraction is a future pass