feat(auth): M9 Part 2 — native in-app SSO via the mobile bridge
All checks were successful
PR Checks / android-build (pull_request) Successful in 20m34s
All checks were successful
PR Checks / android-build (pull_request) Successful in 20m34s
Add the app client for the Mobile SSO Authorization Bridge (PLAN.md §4.2): native "Sign in with <provider>" without shipping any OAuth secret. - Pkce: pure-JVM RFC 7636 S256 verifier/challenge + CSRF state, encoded to match the backend's base64url(SHA-256) exactly. - SsoAuthManager (Singleton): mints PKCE+state, builds the /auth/mobile/sso/start URL for a Custom Tab, verifies the returned state, exchanges the one-time code with the stashed verifier, and drives the existing SessionManager.onSignedIn — no new token-storage or refresh code. Pending flow is in-memory (fails closed on process death). Exposes an outcome StateFlow the login screen consumes. - SsoApi + DTOs: GET /auth/providers discovery and POST /auth/mobile/sso/exchange (tagged NO_SESSION so a credential 401 isn't read as an expired session). - MainActivity: runicgateway://auth/callback intent-filter + singleTop; parses the callback Uri (the Android edge) and hands raw params to SsoAuthManager. - LoginScreen/ViewModel: render a button per discovered provider, opening the bridge in a Custom Tab; fall back to the website login hand-off when none. Additive — no other screen's data flow changes; no backend work. Custom scheme only for now (App Links deferred, APP_LINKS.md). Tests (JVM, +14): Pkce vector/charset, start-URL building, and the full complete() flow over a fake SsoApi + real SessionManager (success signs in; state mismatch / missing pending fail without exchanging; error callback → declined; 401 → expired-code; replay finds no pending). Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NgyHnrNa8WwG3doxvxjuCr
This commit is contained in:
@@ -61,11 +61,14 @@
|
||||
<string name="login_register">Create an account</string>
|
||||
<string name="login_forgot">Forgot your password?</string>
|
||||
<string name="login_sso">Sign in with Google or Discord (on the website)</string>
|
||||
<!-- %1$s is the provider name, e.g. "Google" or "Discord" (native SSO, M9). -->
|
||||
<string name="login_sso_provider">Sign in with %1$s</string>
|
||||
<string name="login_error_credentials">Incorrect username or password.</string>
|
||||
<string name="login_error_code">That code didn\'t match. Try the current code.</string>
|
||||
<string name="login_error_rate_limited">Too many attempts. Please try again shortly.</string>
|
||||
<string name="login_error_server">Something went wrong. Please try again.</string>
|
||||
<string name="login_error_network">Can\'t reach the site. Check your connection and try again.</string>
|
||||
<string name="login_error_sso">Couldn\'t complete that sign-in. Please try again.</string>
|
||||
|
||||
<!-- ── Auth: account (§5, §6.3) ────────────────────────────────────── -->
|
||||
<string name="account_title">My account</string>
|
||||
|
||||
Reference in New Issue
Block a user