Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
487 changes: 487 additions & 0 deletions docs/superpowers/plans/2026-04-23-oidc-login-implementation.md

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions resources/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,14 @@
"login.proxy_settings.error.invalid_port": "Proxy port must be a number between 1 and 65535.",
"login.button.login": "Login",
"login.button.create_account": "Create account",
"login.button.continue_in_browser": "Continue in browser",
"login.button.cancel_oidc": "Cancel sign-in",
"login.oidc.info_title": "Browser sign-in required",
"login.oidc.info_body": "This server uses a secure web sign-in. We'll open your browser — after you log in there, this app finishes automatically.",
"login.oidc.waiting_body": "Finish signing in on your browser, then return to Robrix.",
"login.oidc.cancelled": "Sign-in was cancelled. Click Login again to retry.",
"login.status.checking_homeserver.title": "Checking homeserver...",
"login.status.checking_homeserver.body": "Detecting how this server handles sign-in.",
"login.sso.prompt": "Or, login with an SSO provider:",
"login.account_prompt.no_account": "Don't have an account?",
"login.account_prompt.already_have": "Already have an account?",
Expand Down
8 changes: 8 additions & 0 deletions resources/i18n/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,14 @@
"login.proxy_settings.error.invalid_port": "代理端口必须是 1 到 65535 之间的数字。",
"login.button.login": "登录",
"login.button.create_account": "创建账号",
"login.button.continue_in_browser": "在浏览器中继续",
"login.button.cancel_oidc": "取消登录",
"login.oidc.info_title": "需要浏览器登录",
"login.oidc.info_body": "该服务器使用网页安全登录。我们会打开系统浏览器——你在浏览器里完成登录后,本应用会自动继续。",
"login.oidc.waiting_body": "请在浏览器中完成登录,然后回到 Robrix。",
"login.oidc.cancelled": "登录已取消。再次点击登录可重试。",
"login.status.checking_homeserver.title": "正在检查服务器...",
"login.status.checking_homeserver.body": "正在识别该服务器的登录方式。",
"login.sso.prompt": "或者,使用 SSO 提供商登录:",
"login.account_prompt.no_account": "还没有账号?",
"login.account_prompt.already_have": "已经有账号了?",
Expand Down
67 changes: 67 additions & 0 deletions src/homeserver.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
//! Shared homeserver capability discovery state used by login and register.

use makepad_widgets::ActionDefaultRef;
use matrix_sdk::ruma::api::client::uiaa::UiaaInfo;

/// Homeserver capabilities discovered before branching into auth/register flows.
#[derive(Clone, Debug)]
pub struct HsCapabilities {
/// Normalized base URL the client will use.
pub base_url: String,
/// True iff the server advertises `m.authentication.issuer` in
/// `.well-known/matrix/client` (MSC2965 / MAS delegation).
pub is_mas_native_oidc: bool,
/// True iff `POST /_matrix/client/v3/register` with empty body returns
/// 401 with parseable UIAA flows (NOT 403 M_FORBIDDEN).
pub registration_enabled: bool,
/// Optional UIAA probe result (empty when server requires MAS).
pub uiaa_probe: Option<UiaaInfo>,
/// Identity providers harvested from `/_matrix/client/v3/login`.
pub sso_providers: Vec<IdentityProviderSummary>,
/// URL to open in the system browser for MAS self-registration.
pub mas_signup_url: Option<String>,
/// OAuth issuer discovered from `.well-known`, used by MAS login.
pub mas_issuer_url: Option<String>,
}

/// Minimal info per identity provider. Full matrix-sdk type is not
/// used because we only need name + id at this phase.
#[derive(Clone, Debug)]
pub struct IdentityProviderSummary {
pub id: String,
pub name: String,
pub icon_url: Option<String>,
}

/// Shared capability probe result action.
#[derive(Clone, Debug, Default)]
pub enum CapabilityProbeAction {
/// `requested_url` is echoed so screens can drop out-of-order responses.
Discovered { requested_url: String, caps: Box<HsCapabilities> },
/// `requested_url` is echoed so screens can drop out-of-order responses.
Failed { requested_url: String, error: String },
#[default]
None,
}

impl ActionDefaultRef for CapabilityProbeAction {
fn default_ref() -> &'static Self {
static DEFAULT: CapabilityProbeAction = CapabilityProbeAction::None;
&DEFAULT
}
}

/// Outcome classification of capability discovery for login.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum LoginMode {
MasOidc,
Password,
}

pub fn login_mode(caps: &HsCapabilities) -> LoginMode {
if caps.is_mas_native_oidc {
LoginMode::MasOidc
} else {
LoginMode::Password
}
}
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ pub mod i18n;

/// Login screen
pub mod login;
/// Shared homeserver capability discovery state.
pub mod homeserver;
/// Account registration flow
pub mod register;
/// Logout confirmation and state management
Expand Down
Loading