Skip to content

feat(register): Auto-login after MAS web registration (Phase 3b) #116

@TigerInYourDream

Description

@TigerInYourDream

Summary

After a user completes MAS (Matrix Authentication Service) registration in the system browser, robrix2 should automatically sign them in — without requiring them to type their freshly-created credentials back into the app.

This closes the last UX gap between robrix2 and Element Desktop on MAS-delegated servers (matrix.org, account.matrix.org, etc.).

Background

Phase 3a (PR #114 + #115) delivered in-app registration for two of the three server types:

Server type Phase 3a behavior Auto-login?
UIAA servers (Palpo, default Synapse) Inline form → m.login.dummy → authenticated client ✅ Yes (register IS login)
MAS-delegated (matrix.org) Opens <issuer>/register in system browser ❌ No — user must return and login manually
Disabled Error message N/A

The MAS path works (matrix.org registration completes successfully in the browser), but the user then has to:

  1. Switch back to robrix2
  2. Tap "Sign in"
  3. Retype their new localpart + password

Element Desktop (pre-MSC2965) has the same limitation; Element X and Element Web get auto-login via OIDC authorization-code flow. This issue covers closing that gap for robrix2.

Desired UX

User clicks \"Create account\" in robrix2
  → browser opens account.matrix.org/register with OAuth params (client_id, redirect_uri=robrix://oauth-callback, state, PKCE challenge)
  → user registers + consents in browser
  → browser navigates to robrix://oauth-callback?code=...&state=...
  → OS routes the URL to robrix2 (macOS LaunchServices / Linux xdg-open / Windows registry)
  → robrix2 exchanges code + PKCE verifier → access token → authenticated client → main UI

No retyping. Matches Element X.

Technical Approach

Required pieces

  1. MSC2966 dynamic client registration
    POST <issuer>/oauth2/registration with redirect_uri = robrix://oauth-callback.
    Cache the returned client_id per homeserver.

  2. PKCE + authorization code flow
    Generate code_verifier + code_challenge (S256), open authorize URL with state for CSRF.

  3. URL scheme handler
    OS-level registration so robrix://oauth-callback?... wakes robrix2 (or delivers to the running instance).

  4. Single-instance enforcement
    If a second robrix launches to handle the callback, forward the URL to the already-running instance. Otherwise the callback lands in a fresh process with no pending OAuth state.

  5. Code-to-token exchange
    POST <issuer>/oauth2/token with code, code_verifier, client_id. Receive access token + refresh token → hand to matrix_auth()finalize_authenticated_client.

Existing assets (already in tree)

  • packaging/Info.plist already declares robrix:// and matrix:// under CFBundleURLSchemes. macOS LaunchServices will route the callback once a handler is registered at runtime.
  • RegisterAction::RegistrationSuccess → main-UI transition already exists in app.rs (reused from Phase 3a). The OAuth path just needs to dispatch the same action after token exchange.
  • build_client_session_persisted + finalize_authenticated_client in sliding_sync.rs already handle session persistence.

Missing pieces

  • matrix-sdk experimental-oidc feature is NOT currently enabled in Cargo.toml. Current features: e2e-encryption, automatic-room-key-forwarding, markdown, sqlite, rustls-tls, bundled-sqlite, sso-login. Enabling experimental-oidc pulls in mas-oidc-client and related deps — needs review for binary size / license / compile-time impact.
  • No URL scheme handler wired up at runtime. Info.plist entries are declarative only; macOS still needs the app to register an NSAppleEventManager handler (or equivalent via a crate like robius-url-handler).

Dependency Risks

robius-url-handler (the natural candidate)

  • Repo: project-robius/robius-url-handler
  • Last commit: 2024-06-26 (2 years stale as of 2026-04-22)
  • Only 7 commits total
  • Only macOS has a complete implementation; Linux/Windows paths are stubs
  • Before Phase 3b starts, either:
    • (a) audit whether the crate still compiles + works against current Makepad/Robius stack, or
    • (b) fork/vendor the macOS code and accept we're the maintainers for this path

matrix-sdk OIDC feature

  • experimental-oidc is gated behind an experimental flag upstream, meaning API can churn
  • Worth re-checking stability at the time Phase 3b starts — if it's been promoted to stable, use the stable API path instead

Platform Support Matrix

Platform Phase 3b deliverable
macOS Full auto-login via Info.plist + NSAppleEventManager handler
Linux Deferred — requires xdg-mime default + .desktop MimeType entry; robius-url-handler Linux impl is a stub
Windows Deferred — requires registry entries via installer; robius-url-handler Windows impl is a stub
iOS/Android Separate work (Universal Links / App Links + different matrix-sdk OIDC integration)

Recommendation: Phase 3b ships macOS only. Linux/Windows users stay on the manual re-login path until a separate Phase 3c addresses them. This is progressive enhancement — no regression for other platforms, just incremental win on the platform where the deps work today.

Out of Scope (explicitly deferred to later phases)

  • zxcvbn password strength scoring — pure UX polish for UIAA path; Phase 5
  • Username availability debounce check (/register/available) — pure UX polish; Phase 5
  • UIAA m.login.terms / m.login.registration_token stages — needs test servers; Phase 4
  • Email / msisdn 3pid verification — Phase 4
  • OS-specific device name — Phase 5
  • i18n for register-flow strings — Phase 5

Effort Estimate

~5–6 days for macOS-only implementation:

  • Day 1: audit robius-url-handler + matrix-sdk OIDC feature; decide vendor vs. depend
  • Day 2: MSC2966 dynamic registration + client_id cache
  • Day 3: PKCE + authorize URL construction + state store
  • Day 4: URL scheme handler wiring + single-instance forwarding
  • Day 5: token exchange + finalize_authenticated_client integration
  • Day 6: manual test matrix (matrix.org happy path, state mismatch, user-cancelled in browser, second-app-instance, token refresh)

Why This Is Deferred (Not Included in Phase 3a)

References

Acceptance Criteria (when Phase 3b is picked up)

  • macOS: register on matrix.org in browser → app auto-switches to main UI with the new account logged in
  • State mismatch in callback → error surfaced in RegisterScreen, not silent
  • User cancels in browser → RegisterScreen returns to form-entry state (not stuck on "Creating your account…")
  • Second robrix launch from callback URL → forwards URL to running instance, does not start a new client
  • Linux/Windows: registration still works via existing manual re-login path (no regression)
  • Refresh token persisted; next app launch doesn't re-prompt for login

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions