From 47d411f641ff01e33d3f94c3af22d24366fbfaec Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Fri, 28 Nov 2025 15:51:43 +0100 Subject: [PATCH] Option to skip confirmation when registering through an upstream OAuth provider --- crates/cli/src/sync.rs | 1 + crates/config/src/sections/upstream_oauth2.rs | 34 +++++++++++++++++-- .../src/upstream_oauth2/provider.rs | 3 ++ docs/config.schema.json | 6 +++- docs/reference/configuration.md | 8 +++++ 5 files changed, 48 insertions(+), 4 deletions(-) diff --git a/crates/cli/src/sync.rs b/crates/cli/src/sync.rs index 1aa8f7402..6c250d9c8 100644 --- a/crates/cli/src/sync.rs +++ b/crates/cli/src/sync.rs @@ -58,6 +58,7 @@ fn map_claims_imports( subject: mas_data_model::UpstreamOAuthProviderSubjectPreference { template: config.subject.template.clone(), }, + skip_confirmation: config.skip_confirmation, localpart: mas_data_model::UpstreamOAuthProviderLocalpartPreference { action: map_import_action(config.localpart.action), template: config.localpart.template.clone(), diff --git a/crates/config/src/sections/upstream_oauth2.rs b/crates/config/src/sections/upstream_oauth2.rs index 53eae7a1b..4fc5f16b8 100644 --- a/crates/config/src/sections/upstream_oauth2.rs +++ b/crates/config/src/sections/upstream_oauth2.rs @@ -118,6 +118,26 @@ impl ConfigurationSection for UpstreamOAuth2Config { } } + if provider.claims_imports.skip_confirmation { + if provider.claims_imports.localpart.action != ImportAction::Require { + return Err(annotate(figment::Error::custom( + "The field `action` must be `require` when `skip_confirmation` is set to `true`", + )).with_path("claims_imports.localpart").into()); + } + + if provider.claims_imports.email.action == ImportAction::Suggest { + return Err(annotate(figment::Error::custom( + "The field `action` must not be `suggest` when `skip_confirmation` is set to `true`", + )).with_path("claims_imports.email").into()); + } + + if provider.claims_imports.displayname.action == ImportAction::Suggest { + return Err(annotate(figment::Error::custom( + "The field `action` must not be `suggest` when `skip_confirmation` is set to `true`", + )).with_path("claims_imports.displayname").into()); + } + } + if matches!( provider.claims_imports.localpart.on_conflict, OnConflict::Add @@ -127,7 +147,7 @@ impl ConfigurationSection for UpstreamOAuth2Config { ) { return Err(annotate(figment::Error::custom( "The field `action` must be either `force` or `require` when `on_conflict` is set to `add`", - )).into()); + )).with_path("claims_imports.localpart").into()); } } @@ -326,6 +346,13 @@ pub struct ClaimsImports { #[serde(default, skip_serializing_if = "SubjectImportPreference::is_default")] pub subject: SubjectImportPreference, + /// Whether to skip the interactive screen prompting the user to confirm the + /// attributes that are being imported. This requires `localpart.action` to + /// be `require` and other attribute actions to be either `ignore`, `force` + /// or `require` + #[serde(default, skip_serializing_if = "std::ops::Not::not")] + pub skip_confirmation: bool, + /// Import the localpart of the MXID #[serde(default, skip_serializing_if = "LocalpartImportPreference::is_default")] pub localpart: LocalpartImportPreference, @@ -337,8 +364,7 @@ pub struct ClaimsImports { )] pub displayname: DisplaynameImportPreference, - /// Import the email address of the user based on the `email` and - /// `email_verified` claims + /// Import the email address of the user #[serde(default, skip_serializing_if = "EmailImportPreference::is_default")] pub email: EmailImportPreference, @@ -354,8 +380,10 @@ impl ClaimsImports { const fn is_default(&self) -> bool { self.subject.is_default() && self.localpart.is_default() + && !self.skip_confirmation && self.displayname.is_default() && self.email.is_default() + && self.account_name.is_default() } } diff --git a/crates/data-model/src/upstream_oauth2/provider.rs b/crates/data-model/src/upstream_oauth2/provider.rs index be42cb5a5..318f1e680 100644 --- a/crates/data-model/src/upstream_oauth2/provider.rs +++ b/crates/data-model/src/upstream_oauth2/provider.rs @@ -312,6 +312,9 @@ pub struct ClaimsImports { #[serde(default)] pub subject: SubjectPreference, + #[serde(default)] + pub skip_confirmation: bool, + #[serde(default)] pub localpart: LocalpartPreference, diff --git a/docs/config.schema.json b/docs/config.schema.json index cda68f145..510c0e765 100644 --- a/docs/config.schema.json +++ b/docs/config.schema.json @@ -2467,6 +2467,10 @@ } ] }, + "skip_confirmation": { + "description": "Whether to skip the interactive screen prompting the user to confirm the\n attributes that are being imported. This requires `localpart.action` to\n be `require` and other attribute actions to be either `ignore`, `force`\n or `require`", + "type": "boolean" + }, "localpart": { "description": "Import the localpart of the MXID", "allOf": [ @@ -2484,7 +2488,7 @@ ] }, "email": { - "description": "Import the email address of the user based on the `email` and\n `email_verified` claims", + "description": "Import the email address of the user", "allOf": [ { "$ref": "#/definitions/EmailImportPreference" diff --git a/docs/reference/configuration.md b/docs/reference/configuration.md index 58637f2d8..d8bb41129 100644 --- a/docs/reference/configuration.md +++ b/docs/reference/configuration.md @@ -771,6 +771,14 @@ upstream_oauth2: subject: #template: "{{ user.sub }}" + # By default, new users will see a screen confirming the attributes they + # are about to have on their account. + # + # Setting this to `true` allows skipping this screen, but requires the + # `localpart.action` to be set to `require` and the other attributes + # actions to be set to `ignore`, `force` or `require`. + #skip_confirmation: false + # The localpart is the local part of the user's Matrix ID. # For example, on the `example.com` server, if the localpart is `alice`, # the user's Matrix ID will be `@alice:example.com`.