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:
- Switch back to robrix2
- Tap "Sign in"
- 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
-
MSC2966 dynamic client registration
POST <issuer>/oauth2/registration with redirect_uri = robrix://oauth-callback.
Cache the returned client_id per homeserver.
-
PKCE + authorization code flow
Generate code_verifier + code_challenge (S256), open authorize URL with state for CSRF.
-
URL scheme handler
OS-level registration so robrix://oauth-callback?... wakes robrix2 (or delivers to the running instance).
-
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.
-
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)
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:
m.login.dummy→ authenticated client<issuer>/registerin system browserThe MAS path works (matrix.org registration completes successfully in the browser), but the user then has to:
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
No retyping. Matches Element X.
Technical Approach
Required pieces
MSC2966 dynamic client registration
POST
<issuer>/oauth2/registrationwith redirect_uri =robrix://oauth-callback.Cache the returned
client_idper homeserver.PKCE + authorization code flow
Generate
code_verifier+code_challenge(S256), open authorize URL withstatefor CSRF.URL scheme handler
OS-level registration so
robrix://oauth-callback?...wakes robrix2 (or delivers to the running instance).Single-instance enforcement
If a second
robrixlaunches 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.Code-to-token exchange
POST
<issuer>/oauth2/tokenwithcode,code_verifier,client_id. Receive access token + refresh token → hand tomatrix_auth()→finalize_authenticated_client.Existing assets (already in tree)
packaging/Info.plistalready declaresrobrix://andmatrix://underCFBundleURLSchemes. macOS LaunchServices will route the callback once a handler is registered at runtime.RegisterAction::RegistrationSuccess→ main-UI transition already exists inapp.rs(reused from Phase 3a). The OAuth path just needs to dispatch the same action after token exchange.build_client_session_persisted+finalize_authenticated_clientinsliding_sync.rsalready handle session persistence.Missing pieces
matrix-sdkexperimental-oidcfeature is NOT currently enabled inCargo.toml. Current features:e2e-encryption, automatic-room-key-forwarding, markdown, sqlite, rustls-tls, bundled-sqlite, sso-login. Enablingexperimental-oidcpulls inmas-oidc-clientand related deps — needs review for binary size / license / compile-time impact.Info.plistentries are declarative only; macOS still needs the app to register anNSAppleEventManagerhandler (or equivalent via a crate likerobius-url-handler).Dependency Risks
robius-url-handler(the natural candidate)project-robius/robius-url-handlermatrix-sdkOIDC featureexperimental-oidcis gated behind an experimental flag upstream, meaning API can churnPlatform Support Matrix
Info.plist+NSAppleEventManagerhandlerxdg-mime default+.desktopMimeType entry;robius-url-handlerLinux impl is a stubrobius-url-handlerWindows impl is a stubRecommendation: 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)
/register/available) — pure UX polish; Phase 5m.login.terms/m.login.registration_tokenstages — needs test servers; Phase 4Effort Estimate
~5–6 days for macOS-only implementation:
robius-url-handler+matrix-sdkOIDC feature; decide vendor vs. dependfinalize_authenticated_clientintegrationWhy This Is Deferred (Not Included in Phase 3a)
robius-url-handlerstaleness +experimental-oidcgate) — starting Phase 3b means either accepting that risk or doing dep-triage first; PR feat(register): Phase 3a — UIAA dummy flow for self-hosted servers #115 shouldn't wait on thatReferences
specs/task-register-flow.spec.md(original Phase 1-5 spec)Acceptance Criteria (when Phase 3b is picked up)