diff --git a/crates/cli/src/sync.rs b/crates/cli/src/sync.rs index c4aeb9a9c..d7a331d11 100644 --- a/crates/cli/src/sync.rs +++ b/crates/cli/src/sync.rs @@ -341,6 +341,7 @@ pub async fn config_sync( forward_login_hint: provider.forward_login_hint, ui_order, on_backchannel_logout, + registration_token_required: provider.registration_token_required, }, ) .await?; diff --git a/crates/cli/src/util.rs b/crates/cli/src/util.rs index 67bd87acf..97d81e900 100644 --- a/crates/cli/src/util.rs +++ b/crates/cli/src/util.rs @@ -218,6 +218,14 @@ pub fn site_config_from_config( user_session_inactivity_ttl: c.expire_user_sessions.then_some(c.ttl), }); + if account_config.registration_token_required { + tracing::warn!( + "`account.registration_token_required` is deprecated. use \ + `account.password_registration_token_required` and per-provider \ + `registration_token_required` instead" + ); + } + Ok(SiteConfig { access_token_ttl: experimental_config.access_token_ttl, compat_token_ttl: experimental_config.compat_token_ttl, @@ -229,6 +237,7 @@ pub fn site_config_from_config( password_registration_enabled: password_config.enabled() && account_config.password_registration_enabled, password_registration_email_required: account_config.password_registration_email_required, + password_registration_token_required: account_config.password_registration_token_required, registration_token_required: account_config.registration_token_required, email_change_allowed: account_config.email_change_allowed, displayname_change_allowed: account_config.displayname_change_allowed, diff --git a/crates/config/src/sections/account.rs b/crates/config/src/sections/account.rs index a96fcae93..fb87ee069 100644 --- a/crates/config/src/sections/account.rs +++ b/crates/config/src/sections/account.rs @@ -69,6 +69,15 @@ pub struct AccountConfig { #[serde(default = "default_false", skip_serializing_if = "is_default_false")] pub password_recovery_enabled: bool, + /// Whether registration tokens are required for password registrations. + /// Defaults to `false`. + /// + /// When enabled, users must provide a valid registration token during + /// password registration. This has no effect if password registration + /// is disabled. + #[serde(default = "default_false", skip_serializing_if = "is_default_false")] + pub password_registration_token_required: bool, + /// Whether users are allowed to delete their own account. Defaults to /// `true`. #[serde(default = "default_true", skip_serializing_if = "is_default_true")] @@ -80,12 +89,8 @@ pub struct AccountConfig { #[serde(default = "default_false", skip_serializing_if = "is_default_false")] pub login_with_email_allowed: bool, - /// Whether registration tokens are required for password registrations. - /// Defaults to `false`. - /// - /// When enabled, users must provide a valid registration token during - /// password registration. This has no effect if password registration - /// is disabled. + /// Whether registration tokens are required for password registrations + /// This is deprecated in favor of `password_registration_token_required` #[serde(default = "default_false", skip_serializing_if = "is_default_false")] pub registration_token_required: bool, } @@ -99,9 +104,10 @@ impl Default for AccountConfig { password_registration_email_required: default_true(), password_change_allowed: default_true(), password_recovery_enabled: default_false(), + password_registration_token_required: default_false(), + registration_token_required: default_false(), account_deactivation_allowed: default_true(), login_with_email_allowed: default_false(), - registration_token_required: default_false(), } } } @@ -114,9 +120,10 @@ impl AccountConfig { && is_default_true(&self.displayname_change_allowed) && is_default_true(&self.password_change_allowed) && is_default_false(&self.password_recovery_enabled) + && is_default_false(&self.password_registration_token_required) + && is_default_false(&self.registration_token_required) && is_default_true(&self.account_deactivation_allowed) && is_default_false(&self.login_with_email_allowed) - && is_default_false(&self.registration_token_required) } } diff --git a/crates/config/src/sections/upstream_oauth2.rs b/crates/config/src/sections/upstream_oauth2.rs index 5e87927f8..188695fa5 100644 --- a/crates/config/src/sections/upstream_oauth2.rs +++ b/crates/config/src/sections/upstream_oauth2.rs @@ -511,6 +511,7 @@ impl OnBackchannelLogout { #[serde_as] #[skip_serializing_none] #[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] +#[allow(clippy::struct_excessive_bools)] pub struct Provider { /// Whether this provider is enabled. /// @@ -691,6 +692,12 @@ pub struct Provider { /// Defaults to `do_nothing`. #[serde(default, skip_serializing_if = "OnBackchannelLogout::is_default")] pub on_backchannel_logout: OnBackchannelLogout, + + /// Whether or not to require a registration token on `OAuth2` auth + /// + /// Defaults to `false` + #[serde(default)] + pub registration_token_required: bool, } impl Provider { diff --git a/crates/data-model/src/site_config.rs b/crates/data-model/src/site_config.rs index 3a913cf3b..d57bc43c7 100644 --- a/crates/data-model/src/site_config.rs +++ b/crates/data-model/src/site_config.rs @@ -80,6 +80,11 @@ pub struct SiteConfig { pub password_registration_email_required: bool, /// Whether registration tokens are required for password registrations. + pub password_registration_token_required: bool, + + /// Whether registration tokens are required globally for password + /// registrations. Deprecated in favor of + /// `password_registration_token_required` pub registration_token_required: bool, /// Whether users can change their email. diff --git a/crates/data-model/src/upstream_oauth2/provider.rs b/crates/data-model/src/upstream_oauth2/provider.rs index 94f6c2e51..7a7bb9165 100644 --- a/crates/data-model/src/upstream_oauth2/provider.rs +++ b/crates/data-model/src/upstream_oauth2/provider.rs @@ -285,6 +285,7 @@ pub struct UpstreamOAuthProvider { pub additional_authorization_parameters: Vec<(String, String)>, pub forward_login_hint: bool, pub on_backchannel_logout: OnBackchannelLogout, + pub registration_token_required: bool, } impl PartialOrd for UpstreamOAuthProvider { diff --git a/crates/handlers/src/admin/model.rs b/crates/handlers/src/admin/model.rs index 7936c02f8..f071c089f 100644 --- a/crates/handlers/src/admin/model.rs +++ b/crates/handlers/src/admin/model.rs @@ -723,6 +723,10 @@ pub struct UpstreamOAuthProvider { /// When the provider was disabled. If null, the provider is enabled. disabled_at: Option>, + + /// Whether a registration token is required for registrations via this + /// provider. + registration_token_required: bool, } impl From for UpstreamOAuthProvider { @@ -734,6 +738,7 @@ impl From for UpstreamOAuthProvider { brand_name: provider.brand_name, created_at: provider.created_at, disabled_at: provider.disabled_at, + registration_token_required: provider.registration_token_required, } } } @@ -758,6 +763,7 @@ impl UpstreamOAuthProvider { brand_name: Some("google".to_owned()), created_at: DateTime::default(), disabled_at: None, + registration_token_required: false, }, Self { id: Ulid::from_bytes([0x02; 16]), @@ -766,6 +772,7 @@ impl UpstreamOAuthProvider { brand_name: Some("apple".to_owned()), created_at: DateTime::default(), disabled_at: Some(DateTime::default()), + registration_token_required: false, }, Self { id: Ulid::from_bytes([0x03; 16]), @@ -774,6 +781,7 @@ impl UpstreamOAuthProvider { brand_name: None, created_at: DateTime::default(), disabled_at: None, + registration_token_required: true, }, ] } diff --git a/crates/handlers/src/admin/v1/site_config.rs b/crates/handlers/src/admin/v1/site_config.rs index 21b545550..41eabc91f 100644 --- a/crates/handlers/src/admin/v1/site_config.rs +++ b/crates/handlers/src/admin/v1/site_config.rs @@ -25,7 +25,12 @@ pub struct SiteConfig { /// Whether a valid email address is required for password registrations. pub password_registration_email_required: bool, + pub password_registration_token_required: bool, + /// Whether registration tokens are required for password registrations. + /// Deprecated in favor of `password_registration_token_required` + #[deprecated = "use `password_registration_token_required` instead"] + #[allow(deprecated)] pub registration_token_required: bool, /// Whether users can change their email. @@ -52,6 +57,7 @@ pub struct SiteConfig { pub minimum_password_complexity: u8, } +#[allow(deprecated)] pub fn doc(operation: TransformOperation) -> TransformOperation { operation .id("siteConfig") @@ -63,6 +69,7 @@ pub fn doc(operation: TransformOperation) -> TransformOperation { password_login_enabled: true, password_registration_enabled: true, password_registration_email_required: true, + password_registration_token_required: true, registration_token_required: true, email_change_allowed: true, displayname_change_allowed: true, @@ -76,6 +83,7 @@ pub fn doc(operation: TransformOperation) -> TransformOperation { } #[tracing::instrument(name = "handler.admin.v1.site_config", skip_all)] +#[allow(deprecated)] pub async fn handler( _: CallContext, State(site_config): State, @@ -85,7 +93,8 @@ pub async fn handler( password_login_enabled: site_config.password_login_enabled, password_registration_enabled: site_config.password_registration_enabled, password_registration_email_required: site_config.password_registration_email_required, - registration_token_required: site_config.registration_token_required, + password_registration_token_required: site_config.password_registration_token_required, + registration_token_required: site_config.password_registration_token_required, email_change_allowed: site_config.email_change_allowed, displayname_change_allowed: site_config.displayname_change_allowed, password_change_allowed: site_config.password_change_allowed, diff --git a/crates/handlers/src/admin/v1/upstream_oauth_links/mod.rs b/crates/handlers/src/admin/v1/upstream_oauth_links/mod.rs index 3433aa3ca..33a16f1da 100644 --- a/crates/handlers/src/admin/v1/upstream_oauth_links/mod.rs +++ b/crates/handlers/src/admin/v1/upstream_oauth_links/mod.rs @@ -51,6 +51,7 @@ mod test_utils { forward_login_hint: false, ui_order: 0, on_backchannel_logout: UpstreamOAuthProviderOnBackchannelLogout::DoNothing, + registration_token_required: false, } } } diff --git a/crates/handlers/src/admin/v1/upstream_oauth_providers/get.rs b/crates/handlers/src/admin/v1/upstream_oauth_providers/get.rs index 3700e1a65..caac6aa3a 100644 --- a/crates/handlers/src/admin/v1/upstream_oauth_providers/get.rs +++ b/crates/handlers/src/admin/v1/upstream_oauth_providers/get.rs @@ -119,6 +119,7 @@ mod tests { forward_login_hint: false, on_backchannel_logout: UpstreamOAuthProviderOnBackchannelLogout::DoNothing, ui_order: 0, + registration_token_required: false, }; let provider = repo @@ -164,7 +165,8 @@ mod tests { "human_name": "Google", "brand_name": "google", "created_at": "2022-01-16T14:40:00Z", - "disabled_at": null + "disabled_at": null, + "registration_token_required": false }, "links": { "self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG0MZAA6S4AF7CTV32E" diff --git a/crates/handlers/src/admin/v1/upstream_oauth_providers/list.rs b/crates/handlers/src/admin/v1/upstream_oauth_providers/list.rs index d70bbd299..01f0a60f3 100644 --- a/crates/handlers/src/admin/v1/upstream_oauth_providers/list.rs +++ b/crates/handlers/src/admin/v1/upstream_oauth_providers/list.rs @@ -191,6 +191,7 @@ mod tests { forward_login_hint: false, on_backchannel_logout: UpstreamOAuthProviderOnBackchannelLogout::DoNothing, ui_order: 0, + registration_token_required: false, }; repo.upstream_oauth_provider() @@ -223,6 +224,7 @@ mod tests { forward_login_hint: false, on_backchannel_logout: UpstreamOAuthProviderOnBackchannelLogout::DoNothing, ui_order: 1, + registration_token_required: false, }; let disabled_provider = repo @@ -262,6 +264,7 @@ mod tests { forward_login_hint: false, on_backchannel_logout: UpstreamOAuthProviderOnBackchannelLogout::DoNothing, ui_order: 2, + registration_token_required: false, }; repo.upstream_oauth_provider() @@ -304,7 +307,8 @@ mod tests { "human_name": "Apple ID", "brand_name": "apple", "created_at": "2022-01-16T14:40:00Z", - "disabled_at": "2022-01-16T14:40:00Z" + "disabled_at": "2022-01-16T14:40:00Z", + "registration_token_required": false }, "links": { "self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG07HNEZXNQM2KNBNF6" @@ -323,7 +327,8 @@ mod tests { "human_name": "Microsoft", "brand_name": "microsoft", "created_at": "2022-01-16T14:40:00Z", - "disabled_at": null + "disabled_at": null, + "registration_token_required": false }, "links": { "self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG09AVTNSQFMSR34AJC" @@ -342,7 +347,8 @@ mod tests { "human_name": "Google", "brand_name": "google", "created_at": "2022-01-16T14:40:00Z", - "disabled_at": null + "disabled_at": null, + "registration_token_required": false }, "links": { "self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG0MZAA6S4AF7CTV32E" @@ -392,7 +398,8 @@ mod tests { "human_name": "Microsoft", "brand_name": "microsoft", "created_at": "2022-01-16T14:40:00Z", - "disabled_at": null + "disabled_at": null, + "registration_token_required": false }, "links": { "self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG09AVTNSQFMSR34AJC" @@ -411,7 +418,8 @@ mod tests { "human_name": "Google", "brand_name": "google", "created_at": "2022-01-16T14:40:00Z", - "disabled_at": null + "disabled_at": null, + "registration_token_required": false }, "links": { "self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG0MZAA6S4AF7CTV32E" @@ -461,7 +469,8 @@ mod tests { "human_name": "Apple ID", "brand_name": "apple", "created_at": "2022-01-16T14:40:00Z", - "disabled_at": "2022-01-16T14:40:00Z" + "disabled_at": "2022-01-16T14:40:00Z", + "registration_token_required": false }, "links": { "self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG07HNEZXNQM2KNBNF6" @@ -512,7 +521,8 @@ mod tests { "human_name": "Apple ID", "brand_name": "apple", "created_at": "2022-01-16T14:40:00Z", - "disabled_at": "2022-01-16T14:40:00Z" + "disabled_at": "2022-01-16T14:40:00Z", + "registration_token_required": false }, "links": { "self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG07HNEZXNQM2KNBNF6" @@ -531,7 +541,8 @@ mod tests { "human_name": "Microsoft", "brand_name": "microsoft", "created_at": "2022-01-16T14:40:00Z", - "disabled_at": null + "disabled_at": null, + "registration_token_required": false }, "links": { "self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG09AVTNSQFMSR34AJC" @@ -578,7 +589,8 @@ mod tests { "human_name": "Google", "brand_name": "google", "created_at": "2022-01-16T14:40:00Z", - "disabled_at": null + "disabled_at": null, + "registration_token_required": false }, "links": { "self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG0MZAA6S4AF7CTV32E" @@ -640,7 +652,8 @@ mod tests { "human_name": "Apple ID", "brand_name": "apple", "created_at": "2022-01-16T14:40:00Z", - "disabled_at": "2022-01-16T14:40:00Z" + "disabled_at": "2022-01-16T14:40:00Z", + "registration_token_required": false }, "links": { "self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG07HNEZXNQM2KNBNF6" @@ -659,7 +672,8 @@ mod tests { "human_name": "Microsoft", "brand_name": "microsoft", "created_at": "2022-01-16T14:40:00Z", - "disabled_at": null + "disabled_at": null, + "registration_token_required": false }, "links": { "self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG09AVTNSQFMSR34AJC" @@ -678,7 +692,8 @@ mod tests { "human_name": "Google", "brand_name": "google", "created_at": "2022-01-16T14:40:00Z", - "disabled_at": null + "disabled_at": null, + "registration_token_required": false }, "links": { "self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG0MZAA6S4AF7CTV32E" @@ -737,7 +752,8 @@ mod tests { "human_name": "Microsoft", "brand_name": "microsoft", "created_at": "2022-01-16T14:40:00Z", - "disabled_at": null + "disabled_at": null, + "registration_token_required": false }, "links": { "self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG09AVTNSQFMSR34AJC" @@ -756,7 +772,8 @@ mod tests { "human_name": "Google", "brand_name": "google", "created_at": "2022-01-16T14:40:00Z", - "disabled_at": null + "disabled_at": null, + "registration_token_required": false }, "links": { "self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG0MZAA6S4AF7CTV32E" diff --git a/crates/handlers/src/cleanup_tests.rs b/crates/handlers/src/cleanup_tests.rs index 7b1a74f53..a0bcdba30 100644 --- a/crates/handlers/src/cleanup_tests.rs +++ b/crates/handlers/src/cleanup_tests.rs @@ -200,6 +200,7 @@ async fn create_session_hierarchy( forward_login_hint: false, ui_order: 0, on_backchannel_logout: UpstreamOAuthProviderOnBackchannelLogout::LogoutAll, + registration_token_required: false, }; let provider = repo diff --git a/crates/handlers/src/test_utils.rs b/crates/handlers/src/test_utils.rs index a9e183754..0298a7594 100644 --- a/crates/handlers/src/test_utils.rs +++ b/crates/handlers/src/test_utils.rs @@ -137,6 +137,7 @@ pub fn test_site_config() -> SiteConfig { imprint: None, password_login_enabled: true, password_registration_enabled: true, + password_registration_token_required: false, registration_token_required: false, email_change_allowed: true, displayname_change_allowed: true, diff --git a/crates/handlers/src/upstream_oauth2/cache.rs b/crates/handlers/src/upstream_oauth2/cache.rs index 2e0810933..7ba13d22e 100644 --- a/crates/handlers/src/upstream_oauth2/cache.rs +++ b/crates/handlers/src/upstream_oauth2/cache.rs @@ -433,6 +433,7 @@ mod tests { additional_authorization_parameters: Vec::new(), forward_login_hint: false, on_backchannel_logout: UpstreamOAuthProviderOnBackchannelLogout::DoNothing, + registration_token_required: false, }; // Without any override, it should just use discovery diff --git a/crates/handlers/src/upstream_oauth2/link.rs b/crates/handlers/src/upstream_oauth2/link.rs index e081b0f79..0f27b5cba 100644 --- a/crates/handlers/src/upstream_oauth2/link.rs +++ b/crates/handlers/src/upstream_oauth2/link.rs @@ -1345,6 +1345,7 @@ mod tests { ui_order: 0, on_backchannel_logout: mas_data_model::UpstreamOAuthProviderOnBackchannelLogout::DoNothing, + registration_token_required: false, }, ) .await @@ -1542,6 +1543,7 @@ mod tests { ui_order: 0, on_backchannel_logout: mas_data_model::UpstreamOAuthProviderOnBackchannelLogout::DoNothing, + registration_token_required: false, }, ) .await @@ -1703,6 +1705,7 @@ mod tests { on_backchannel_logout: mas_data_model::UpstreamOAuthProviderOnBackchannelLogout::DoNothing, ui_order: 0, + registration_token_required: false, }, ) .await @@ -1819,6 +1822,7 @@ mod tests { on_backchannel_logout: mas_data_model::UpstreamOAuthProviderOnBackchannelLogout::DoNothing, ui_order: 0, + registration_token_required: false, }, ) .await @@ -1988,6 +1992,7 @@ mod tests { on_backchannel_logout: mas_data_model::UpstreamOAuthProviderOnBackchannelLogout::DoNothing, ui_order: 0, + registration_token_required: false, }, ) .await @@ -2136,6 +2141,7 @@ mod tests { on_backchannel_logout: mas_data_model::UpstreamOAuthProviderOnBackchannelLogout::DoNothing, ui_order: 0, + registration_token_required: false, }, ) .await @@ -2255,6 +2261,7 @@ mod tests { on_backchannel_logout: mas_data_model::UpstreamOAuthProviderOnBackchannelLogout::DoNothing, ui_order: 0, + registration_token_required: false, }, ) .await diff --git a/crates/handlers/src/views/login.rs b/crates/handlers/src/views/login.rs index a4fef8eba..683ebe075 100644 --- a/crates/handlers/src/views/login.rs +++ b/crates/handlers/src/views/login.rs @@ -525,6 +525,7 @@ mod test { forward_login_hint: false, ui_order: 0, on_backchannel_logout: UpstreamOAuthProviderOnBackchannelLogout::DoNothing, + registration_token_required: false, }, ) .await @@ -568,6 +569,7 @@ mod test { forward_login_hint: false, ui_order: 1, on_backchannel_logout: UpstreamOAuthProviderOnBackchannelLogout::DoNothing, + registration_token_required: false, }, ) .await diff --git a/crates/handlers/src/views/register/steps/finish.rs b/crates/handlers/src/views/register/steps/finish.rs index af0b8ef9f..a6c699ac6 100644 --- a/crates/handlers/src/views/register/steps/finish.rs +++ b/crates/handlers/src/views/register/steps/finish.rs @@ -120,8 +120,29 @@ pub(crate) async fn get( ))); } - // Check if the registration token is required and was provided - let registration_token = if site_config.registration_token_required { + let token_required = if let Some(session_id) = + registration.upstream_oauth_authorization_session_id + { + let session = repo + .upstream_oauth_session() + .lookup(session_id) + .await? + .context("Could not load the upstream OAuth authorization session") + .map_err(InternalError::from_anyhow)?; + + let provider = repo + .upstream_oauth_provider() + .lookup(session.provider_id) + .await? + .context("Could not load the upstream OAuth provider") + .map_err(InternalError::from_anyhow)?; + + provider.registration_token_required || site_config.registration_token_required + } else { + site_config.password_registration_token_required || site_config.registration_token_required + }; + + let registration_token = if token_required { if let Some(registration_token_id) = registration.user_registration_token_id { let registration_token = repo .user_registration_token() diff --git a/crates/storage-pg/.sqlx/query-0f2ea548e00b080502edc04ee97ea304d43c336ce80723789ff3e66c0dd4d86c.json b/crates/storage-pg/.sqlx/query-0f2ea548e00b080502edc04ee97ea304d43c336ce80723789ff3e66c0dd4d86c.json deleted file mode 100644 index 1eb87fd3f..000000000 --- a/crates/storage-pg/.sqlx/query-0f2ea548e00b080502edc04ee97ea304d43c336ce80723789ff3e66c0dd4d86c.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n INSERT INTO upstream_oauth_providers (\n upstream_oauth_provider_id,\n issuer,\n human_name,\n brand_name,\n scope,\n token_endpoint_auth_method,\n token_endpoint_signing_alg,\n id_token_signed_response_alg,\n fetch_userinfo,\n userinfo_signed_response_alg,\n client_id,\n encrypted_client_secret,\n claims_imports,\n authorization_endpoint_override,\n token_endpoint_override,\n userinfo_endpoint_override,\n jwks_uri_override,\n discovery_mode,\n pkce_mode,\n response_mode,\n additional_parameters,\n forward_login_hint,\n ui_order,\n on_backchannel_logout,\n created_at\n ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10,\n $11, $12, $13, $14, $15, $16, $17, $18, $19, $20,\n $21, $22, $23, $24, $25)\n ON CONFLICT (upstream_oauth_provider_id)\n DO UPDATE\n SET\n issuer = EXCLUDED.issuer,\n human_name = EXCLUDED.human_name,\n brand_name = EXCLUDED.brand_name,\n scope = EXCLUDED.scope,\n token_endpoint_auth_method = EXCLUDED.token_endpoint_auth_method,\n token_endpoint_signing_alg = EXCLUDED.token_endpoint_signing_alg,\n id_token_signed_response_alg = EXCLUDED.id_token_signed_response_alg,\n fetch_userinfo = EXCLUDED.fetch_userinfo,\n userinfo_signed_response_alg = EXCLUDED.userinfo_signed_response_alg,\n disabled_at = NULL,\n client_id = EXCLUDED.client_id,\n encrypted_client_secret = EXCLUDED.encrypted_client_secret,\n claims_imports = EXCLUDED.claims_imports,\n authorization_endpoint_override = EXCLUDED.authorization_endpoint_override,\n token_endpoint_override = EXCLUDED.token_endpoint_override,\n userinfo_endpoint_override = EXCLUDED.userinfo_endpoint_override,\n jwks_uri_override = EXCLUDED.jwks_uri_override,\n discovery_mode = EXCLUDED.discovery_mode,\n pkce_mode = EXCLUDED.pkce_mode,\n response_mode = EXCLUDED.response_mode,\n additional_parameters = EXCLUDED.additional_parameters,\n forward_login_hint = EXCLUDED.forward_login_hint,\n ui_order = EXCLUDED.ui_order,\n on_backchannel_logout = EXCLUDED.on_backchannel_logout\n RETURNING created_at\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "created_at", - "type_info": "Timestamptz" - } - ], - "parameters": { - "Left": [ - "Uuid", - "Text", - "Text", - "Text", - "Text", - "Text", - "Text", - "Text", - "Bool", - "Text", - "Text", - "Text", - "Jsonb", - "Text", - "Text", - "Text", - "Text", - "Text", - "Text", - "Text", - "Jsonb", - "Bool", - "Int4", - "Text", - "Timestamptz" - ] - }, - "nullable": [ - false - ] - }, - "hash": "0f2ea548e00b080502edc04ee97ea304d43c336ce80723789ff3e66c0dd4d86c" -} diff --git a/crates/storage-pg/.sqlx/query-3312f901f70c3b69e0d315206c31ffe11da64835ae297c9277271b8971d5de81.json b/crates/storage-pg/.sqlx/query-212e0ce75c5e8b73e95b3a9505365192f1b5c133fcda65894add35dc5ae62295.json similarity index 80% rename from crates/storage-pg/.sqlx/query-3312f901f70c3b69e0d315206c31ffe11da64835ae297c9277271b8971d5de81.json rename to crates/storage-pg/.sqlx/query-212e0ce75c5e8b73e95b3a9505365192f1b5c133fcda65894add35dc5ae62295.json index 3f837630f..de285dbba 100644 --- a/crates/storage-pg/.sqlx/query-3312f901f70c3b69e0d315206c31ffe11da64835ae297c9277271b8971d5de81.json +++ b/crates/storage-pg/.sqlx/query-212e0ce75c5e8b73e95b3a9505365192f1b5c133fcda65894add35dc5ae62295.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n INSERT INTO upstream_oauth_providers (\n upstream_oauth_provider_id,\n issuer,\n human_name,\n brand_name,\n scope,\n token_endpoint_auth_method,\n token_endpoint_signing_alg,\n id_token_signed_response_alg,\n fetch_userinfo,\n userinfo_signed_response_alg,\n client_id,\n encrypted_client_secret,\n claims_imports,\n authorization_endpoint_override,\n token_endpoint_override,\n userinfo_endpoint_override,\n jwks_uri_override,\n discovery_mode,\n pkce_mode,\n response_mode,\n forward_login_hint,\n on_backchannel_logout,\n created_at\n ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11,\n $12, $13, $14, $15, $16, $17, $18, $19, $20,\n $21, $22, $23)\n ", + "query": "\n INSERT INTO upstream_oauth_providers (\n upstream_oauth_provider_id,\n issuer,\n human_name,\n brand_name,\n scope,\n token_endpoint_auth_method,\n token_endpoint_signing_alg,\n id_token_signed_response_alg,\n fetch_userinfo,\n userinfo_signed_response_alg,\n client_id,\n encrypted_client_secret,\n claims_imports,\n authorization_endpoint_override,\n token_endpoint_override,\n userinfo_endpoint_override,\n jwks_uri_override,\n discovery_mode,\n pkce_mode,\n response_mode,\n forward_login_hint,\n on_backchannel_logout,\n registration_token_required,\n created_at\n ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11,\n $12, $13, $14, $15, $16, $17, $18, $19, $20,\n $21, $22, $23, $24)\n ", "describe": { "columns": [], "parameters": { @@ -27,10 +27,11 @@ "Text", "Bool", "Text", + "Bool", "Timestamptz" ] }, "nullable": [] }, - "hash": "3312f901f70c3b69e0d315206c31ffe11da64835ae297c9277271b8971d5de81" + "hash": "212e0ce75c5e8b73e95b3a9505365192f1b5c133fcda65894add35dc5ae62295" } diff --git a/crates/storage-pg/.sqlx/query-82aaee10fac6db827cc60f8b2571462c443e686349cca3e9788dd93e21aa025e.json b/crates/storage-pg/.sqlx/query-82aaee10fac6db827cc60f8b2571462c443e686349cca3e9788dd93e21aa025e.json new file mode 100644 index 000000000..fd078bbc8 --- /dev/null +++ b/crates/storage-pg/.sqlx/query-82aaee10fac6db827cc60f8b2571462c443e686349cca3e9788dd93e21aa025e.json @@ -0,0 +1,47 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO upstream_oauth_providers (\n upstream_oauth_provider_id,\n issuer,\n human_name,\n brand_name,\n scope,\n token_endpoint_auth_method,\n token_endpoint_signing_alg,\n id_token_signed_response_alg,\n fetch_userinfo,\n userinfo_signed_response_alg,\n client_id,\n encrypted_client_secret,\n claims_imports,\n authorization_endpoint_override,\n token_endpoint_override,\n userinfo_endpoint_override,\n jwks_uri_override,\n discovery_mode,\n pkce_mode,\n response_mode,\n additional_parameters,\n forward_login_hint,\n ui_order,\n on_backchannel_logout,\n registration_token_required,\n created_at\n ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10,\n $11, $12, $13, $14, $15, $16, $17, $18, $19, $20,\n $21, $22, $23, $24, $25, $26)\n ON CONFLICT (upstream_oauth_provider_id)\n DO UPDATE\n SET\n issuer = EXCLUDED.issuer,\n human_name = EXCLUDED.human_name,\n brand_name = EXCLUDED.brand_name,\n scope = EXCLUDED.scope,\n token_endpoint_auth_method = EXCLUDED.token_endpoint_auth_method,\n token_endpoint_signing_alg = EXCLUDED.token_endpoint_signing_alg,\n id_token_signed_response_alg = EXCLUDED.id_token_signed_response_alg,\n fetch_userinfo = EXCLUDED.fetch_userinfo,\n userinfo_signed_response_alg = EXCLUDED.userinfo_signed_response_alg,\n disabled_at = NULL,\n client_id = EXCLUDED.client_id,\n encrypted_client_secret = EXCLUDED.encrypted_client_secret,\n claims_imports = EXCLUDED.claims_imports,\n authorization_endpoint_override = EXCLUDED.authorization_endpoint_override,\n token_endpoint_override = EXCLUDED.token_endpoint_override,\n userinfo_endpoint_override = EXCLUDED.userinfo_endpoint_override,\n jwks_uri_override = EXCLUDED.jwks_uri_override,\n discovery_mode = EXCLUDED.discovery_mode,\n pkce_mode = EXCLUDED.pkce_mode,\n response_mode = EXCLUDED.response_mode,\n additional_parameters = EXCLUDED.additional_parameters,\n forward_login_hint = EXCLUDED.forward_login_hint,\n ui_order = EXCLUDED.ui_order,\n on_backchannel_logout = EXCLUDED.on_backchannel_logout,\n registration_token_required = EXCLUDED.registration_token_required\n RETURNING created_at\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "created_at", + "type_info": "Timestamptz" + } + ], + "parameters": { + "Left": [ + "Uuid", + "Text", + "Text", + "Text", + "Text", + "Text", + "Text", + "Text", + "Bool", + "Text", + "Text", + "Text", + "Jsonb", + "Text", + "Text", + "Text", + "Text", + "Text", + "Text", + "Text", + "Jsonb", + "Bool", + "Int4", + "Text", + "Bool", + "Timestamptz" + ] + }, + "nullable": [ + false + ] + }, + "hash": "82aaee10fac6db827cc60f8b2571462c443e686349cca3e9788dd93e21aa025e" +} diff --git a/crates/storage-pg/.sqlx/query-6589987e88fa9dbbd2bd48acd910e08bab57721007c64ef2597cb09a62100792.json b/crates/storage-pg/.sqlx/query-c80f6e8169a4b0e76168d851bcb1b7b05caef229399ea0f61e0d7a5788034309.json similarity index 91% rename from crates/storage-pg/.sqlx/query-6589987e88fa9dbbd2bd48acd910e08bab57721007c64ef2597cb09a62100792.json rename to crates/storage-pg/.sqlx/query-c80f6e8169a4b0e76168d851bcb1b7b05caef229399ea0f61e0d7a5788034309.json index 6bd2768cc..7ecf3d931 100644 --- a/crates/storage-pg/.sqlx/query-6589987e88fa9dbbd2bd48acd910e08bab57721007c64ef2597cb09a62100792.json +++ b/crates/storage-pg/.sqlx/query-c80f6e8169a4b0e76168d851bcb1b7b05caef229399ea0f61e0d7a5788034309.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT\n upstream_oauth_provider_id,\n issuer,\n human_name,\n brand_name,\n scope,\n client_id,\n encrypted_client_secret,\n token_endpoint_signing_alg,\n token_endpoint_auth_method,\n id_token_signed_response_alg,\n fetch_userinfo,\n userinfo_signed_response_alg,\n created_at,\n disabled_at,\n claims_imports as \"claims_imports: Json\",\n jwks_uri_override,\n authorization_endpoint_override,\n token_endpoint_override,\n userinfo_endpoint_override,\n discovery_mode,\n pkce_mode,\n response_mode,\n additional_parameters as \"additional_parameters: Json>\",\n forward_login_hint,\n on_backchannel_logout\n FROM upstream_oauth_providers\n WHERE upstream_oauth_provider_id = $1\n ", + "query": "\n SELECT\n upstream_oauth_provider_id,\n issuer,\n human_name,\n brand_name,\n scope,\n client_id,\n encrypted_client_secret,\n token_endpoint_signing_alg,\n token_endpoint_auth_method,\n id_token_signed_response_alg,\n fetch_userinfo,\n userinfo_signed_response_alg,\n created_at,\n disabled_at,\n claims_imports as \"claims_imports: Json\",\n jwks_uri_override,\n authorization_endpoint_override,\n token_endpoint_override,\n userinfo_endpoint_override,\n discovery_mode,\n pkce_mode,\n response_mode,\n additional_parameters as \"additional_parameters: Json>\",\n forward_login_hint,\n on_backchannel_logout,\n registration_token_required\n FROM upstream_oauth_providers\n WHERE upstream_oauth_provider_id = $1\n ", "describe": { "columns": [ { @@ -127,6 +127,11 @@ "ordinal": 24, "name": "on_backchannel_logout", "type_info": "Text" + }, + { + "ordinal": 25, + "name": "registration_token_required", + "type_info": "Bool" } ], "parameters": { @@ -159,8 +164,9 @@ true, true, false, + false, false ] }, - "hash": "6589987e88fa9dbbd2bd48acd910e08bab57721007c64ef2597cb09a62100792" + "hash": "c80f6e8169a4b0e76168d851bcb1b7b05caef229399ea0f61e0d7a5788034309" } diff --git a/crates/storage-pg/.sqlx/query-99394fbd9c07d6d24429934b3f7344dfab024b42e47ddc7bd9e551897ba6e9b8.json b/crates/storage-pg/.sqlx/query-ec53297b6bdd23bc15bda823869fa1b3cc6e0991897274636afefcd1a62bdbff.json similarity index 90% rename from crates/storage-pg/.sqlx/query-99394fbd9c07d6d24429934b3f7344dfab024b42e47ddc7bd9e551897ba6e9b8.json rename to crates/storage-pg/.sqlx/query-ec53297b6bdd23bc15bda823869fa1b3cc6e0991897274636afefcd1a62bdbff.json index eb1a801c4..dd993904f 100644 --- a/crates/storage-pg/.sqlx/query-99394fbd9c07d6d24429934b3f7344dfab024b42e47ddc7bd9e551897ba6e9b8.json +++ b/crates/storage-pg/.sqlx/query-ec53297b6bdd23bc15bda823869fa1b3cc6e0991897274636afefcd1a62bdbff.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT\n upstream_oauth_provider_id,\n issuer,\n human_name,\n brand_name,\n scope,\n client_id,\n encrypted_client_secret,\n token_endpoint_signing_alg,\n token_endpoint_auth_method,\n id_token_signed_response_alg,\n fetch_userinfo,\n userinfo_signed_response_alg,\n created_at,\n disabled_at,\n claims_imports as \"claims_imports: Json\",\n jwks_uri_override,\n authorization_endpoint_override,\n token_endpoint_override,\n userinfo_endpoint_override,\n discovery_mode,\n pkce_mode,\n response_mode,\n additional_parameters as \"additional_parameters: Json>\",\n forward_login_hint,\n on_backchannel_logout\n FROM upstream_oauth_providers\n WHERE disabled_at IS NULL\n ORDER BY ui_order ASC, upstream_oauth_provider_id ASC\n ", + "query": "\n SELECT\n upstream_oauth_provider_id,\n issuer,\n human_name,\n brand_name,\n scope,\n client_id,\n encrypted_client_secret,\n token_endpoint_signing_alg,\n token_endpoint_auth_method,\n id_token_signed_response_alg,\n fetch_userinfo,\n userinfo_signed_response_alg,\n created_at,\n disabled_at,\n claims_imports as \"claims_imports: Json\",\n jwks_uri_override,\n authorization_endpoint_override,\n token_endpoint_override,\n userinfo_endpoint_override,\n discovery_mode,\n pkce_mode,\n response_mode,\n additional_parameters as \"additional_parameters: Json>\",\n forward_login_hint,\n on_backchannel_logout,\n registration_token_required\n\n FROM upstream_oauth_providers\n WHERE disabled_at IS NULL\n ORDER BY ui_order ASC, upstream_oauth_provider_id ASC\n ", "describe": { "columns": [ { @@ -127,6 +127,11 @@ "ordinal": 24, "name": "on_backchannel_logout", "type_info": "Text" + }, + { + "ordinal": 25, + "name": "registration_token_required", + "type_info": "Bool" } ], "parameters": { @@ -157,8 +162,9 @@ true, true, false, + false, false ] }, - "hash": "99394fbd9c07d6d24429934b3f7344dfab024b42e47ddc7bd9e551897ba6e9b8" + "hash": "ec53297b6bdd23bc15bda823869fa1b3cc6e0991897274636afefcd1a62bdbff" } diff --git a/crates/storage-pg/migrations/20260403144138_upstream_oauth2_providers_registration_token_required.sql b/crates/storage-pg/migrations/20260403144138_upstream_oauth2_providers_registration_token_required.sql new file mode 100644 index 000000000..7570b5c7d --- /dev/null +++ b/crates/storage-pg/migrations/20260403144138_upstream_oauth2_providers_registration_token_required.sql @@ -0,0 +1,9 @@ +-- Copyright 2026 Element Creations Ltd. +-- +-- SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +-- Please see LICENSE files in the repository root for full details. + +-- Adds a `registration_token_required` column to the UpstreamOauthProvider table + +ALTER TABLE upstream_oauth_providers + ADD COLUMN registration_token_required BOOLEAN NOT NULL DEFAULT FALSE; \ No newline at end of file diff --git a/crates/storage-pg/src/iden.rs b/crates/storage-pg/src/iden.rs index f1af1a5d2..10030f929 100644 --- a/crates/storage-pg/src/iden.rs +++ b/crates/storage-pg/src/iden.rs @@ -156,6 +156,7 @@ pub enum UpstreamOAuthProviders { AuthorizationEndpointOverride, UserinfoEndpointOverride, OnBackchannelLogout, + RegistrationTokenRequired, } #[derive(sea_query::Iden)] diff --git a/crates/storage-pg/src/upstream_oauth2/mod.rs b/crates/storage-pg/src/upstream_oauth2/mod.rs index 12df9d5f0..7c912daf0 100644 --- a/crates/storage-pg/src/upstream_oauth2/mod.rs +++ b/crates/storage-pg/src/upstream_oauth2/mod.rs @@ -79,6 +79,7 @@ mod tests { forward_login_hint: false, ui_order: 0, on_backchannel_logout: UpstreamOAuthProviderOnBackchannelLogout::DoNothing, + registration_token_required: false, }, ) .await @@ -359,6 +360,7 @@ mod tests { forward_login_hint: false, ui_order: 0, on_backchannel_logout: UpstreamOAuthProviderOnBackchannelLogout::DoNothing, + registration_token_required: false, }, ) .await @@ -497,6 +499,7 @@ mod tests { forward_login_hint: false, ui_order: 0, on_backchannel_logout: UpstreamOAuthProviderOnBackchannelLogout::DoNothing, + registration_token_required: false, }, ) .await diff --git a/crates/storage-pg/src/upstream_oauth2/provider.rs b/crates/storage-pg/src/upstream_oauth2/provider.rs index caade738d..2229556e6 100644 --- a/crates/storage-pg/src/upstream_oauth2/provider.rs +++ b/crates/storage-pg/src/upstream_oauth2/provider.rs @@ -73,6 +73,7 @@ struct ProviderLookup { additional_parameters: Option>>, forward_login_hint: bool, on_backchannel_logout: String, + registration_token_required: bool, } impl Node for ProviderLookup { @@ -234,6 +235,7 @@ impl TryFrom for UpstreamOAuthProvider { additional_authorization_parameters, forward_login_hint: value.forward_login_hint, on_backchannel_logout, + registration_token_required: value.registration_token_required, }) } } @@ -293,7 +295,8 @@ impl UpstreamOAuthProviderRepository for PgUpstreamOAuthProviderRepository<'_> { response_mode, additional_parameters as "additional_parameters: Json>", forward_login_hint, - on_backchannel_logout + on_backchannel_logout, + registration_token_required FROM upstream_oauth_providers WHERE upstream_oauth_provider_id = $1 "#, @@ -357,10 +360,11 @@ impl UpstreamOAuthProviderRepository for PgUpstreamOAuthProviderRepository<'_> { response_mode, forward_login_hint, on_backchannel_logout, + registration_token_required, created_at ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, - $21, $22, $23) + $21, $22, $23, $24) "#, Uuid::from(id), params.issuer.as_deref(), @@ -399,6 +403,7 @@ impl UpstreamOAuthProviderRepository for PgUpstreamOAuthProviderRepository<'_> { params.response_mode.as_ref().map(ToString::to_string), params.forward_login_hint, params.on_backchannel_logout.as_str(), + params.registration_token_required, created_at, ) .traced() @@ -431,6 +436,7 @@ impl UpstreamOAuthProviderRepository for PgUpstreamOAuthProviderRepository<'_> { additional_authorization_parameters: params.additional_authorization_parameters, on_backchannel_logout: params.on_backchannel_logout, forward_login_hint: params.forward_login_hint, + registration_token_required: params.registration_token_required, }) } @@ -546,10 +552,11 @@ impl UpstreamOAuthProviderRepository for PgUpstreamOAuthProviderRepository<'_> { forward_login_hint, ui_order, on_backchannel_logout, + registration_token_required, created_at ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, - $21, $22, $23, $24, $25) + $21, $22, $23, $24, $25, $26) ON CONFLICT (upstream_oauth_provider_id) DO UPDATE SET @@ -576,7 +583,8 @@ impl UpstreamOAuthProviderRepository for PgUpstreamOAuthProviderRepository<'_> { additional_parameters = EXCLUDED.additional_parameters, forward_login_hint = EXCLUDED.forward_login_hint, ui_order = EXCLUDED.ui_order, - on_backchannel_logout = EXCLUDED.on_backchannel_logout + on_backchannel_logout = EXCLUDED.on_backchannel_logout, + registration_token_required = EXCLUDED.registration_token_required RETURNING created_at "#, Uuid::from(id), @@ -618,6 +626,7 @@ impl UpstreamOAuthProviderRepository for PgUpstreamOAuthProviderRepository<'_> { params.forward_login_hint, params.ui_order, params.on_backchannel_logout.as_str(), + params.registration_token_required, created_at, ) .traced() @@ -650,6 +659,7 @@ impl UpstreamOAuthProviderRepository for PgUpstreamOAuthProviderRepository<'_> { additional_authorization_parameters: params.additional_authorization_parameters, forward_login_hint: params.forward_login_hint, on_backchannel_logout: params.on_backchannel_logout, + registration_token_required: params.registration_token_required, }) } @@ -874,6 +884,13 @@ impl UpstreamOAuthProviderRepository for PgUpstreamOAuthProviderRepository<'_> { )), ProviderLookupIden::OnBackchannelLogout, ) + .expr_as( + Expr::col(( + UpstreamOAuthProviders::Table, + UpstreamOAuthProviders::RegistrationTokenRequired, + )), + ProviderLookupIden::RegistrationTokenRequired, + ) .from(UpstreamOAuthProviders::Table) .apply_filter(filter) .generate_pagination( @@ -968,7 +985,9 @@ impl UpstreamOAuthProviderRepository for PgUpstreamOAuthProviderRepository<'_> { response_mode, additional_parameters as "additional_parameters: Json>", forward_login_hint, - on_backchannel_logout + on_backchannel_logout, + registration_token_required + FROM upstream_oauth_providers WHERE disabled_at IS NULL ORDER BY ui_order ASC, upstream_oauth_provider_id ASC diff --git a/crates/storage-pg/src/user/registration.rs b/crates/storage-pg/src/user/registration.rs index fff1dd0ad..5a14907b7 100644 --- a/crates/storage-pg/src/user/registration.rs +++ b/crates/storage-pg/src/user/registration.rs @@ -993,6 +993,7 @@ mod tests { forward_login_hint: false, ui_order: 0, on_backchannel_logout: UpstreamOAuthProviderOnBackchannelLogout::DoNothing, + registration_token_required: false, }, ) .await diff --git a/crates/storage-pg/src/user/tests.rs b/crates/storage-pg/src/user/tests.rs index be106c56f..4774e0b45 100644 --- a/crates/storage-pg/src/user/tests.rs +++ b/crates/storage-pg/src/user/tests.rs @@ -772,6 +772,7 @@ async fn test_user_session(pool: PgPool) { ui_order: 0, on_backchannel_logout: mas_data_model::UpstreamOAuthProviderOnBackchannelLogout::DoNothing, + registration_token_required: false, }, ) .await diff --git a/crates/storage/src/upstream_oauth2/provider.rs b/crates/storage/src/upstream_oauth2/provider.rs index 256a74968..df217b433 100644 --- a/crates/storage/src/upstream_oauth2/provider.rs +++ b/crates/storage/src/upstream_oauth2/provider.rs @@ -105,6 +105,9 @@ pub struct UpstreamOAuthProviderParams { /// The behavior when receiving a backchannel logout notification pub on_backchannel_logout: UpstreamOAuthProviderOnBackchannelLogout, + + /// Whether or not to require a registration token on `OAuth2` auth + pub registration_token_required: bool, } /// Filter parameters for listing upstream OAuth 2.0 providers diff --git a/crates/syn2mas/src/mas_writer/snapshots/syn2mas__mas_writer__test__write_user_with_upstream_provider_link.snap b/crates/syn2mas/src/mas_writer/snapshots/syn2mas__mas_writer__test__write_user_with_upstream_provider_link.snap index 7b9173eb3..ace3b5343 100644 --- a/crates/syn2mas/src/mas_writer/snapshots/syn2mas__mas_writer__test__write_user_with_upstream_provider_link.snap +++ b/crates/syn2mas/src/mas_writer/snapshots/syn2mas__mas_writer__test__write_user_with_upstream_provider_link.snap @@ -27,6 +27,7 @@ upstream_oauth_providers: jwks_uri_override: ~ on_backchannel_logout: do_nothing pkce_mode: auto + registration_token_required: "false" response_mode: query scope: openid token_endpoint_auth_method: client_secret_basic diff --git a/crates/syn2mas/src/synapse_reader/config/oidc.rs b/crates/syn2mas/src/synapse_reader/config/oidc.rs index 09baba165..440365dd9 100644 --- a/crates/syn2mas/src/synapse_reader/config/oidc.rs +++ b/crates/syn2mas/src/synapse_reader/config/oidc.rs @@ -347,6 +347,7 @@ impl OidcProvider { additional_authorization_parameters, forward_login_hint: self.forward_login_hint, on_backchannel_logout, + registration_token_required: false, }) } } diff --git a/crates/templates/src/context.rs b/crates/templates/src/context.rs index ef01743e1..0e3deed93 100644 --- a/crates/templates/src/context.rs +++ b/crates/templates/src/context.rs @@ -1754,6 +1754,7 @@ impl TemplateContext for UpstreamRegister { created_at: now, disabled_at: None, on_backchannel_logout: UpstreamOAuthProviderOnBackchannelLogout::DoNothing, + registration_token_required: false, }, )]) } diff --git a/docs/api/spec.json b/docs/api/spec.json index bf6a62f3e..711888287 100644 --- a/docs/api/spec.json +++ b/docs/api/spec.json @@ -36,6 +36,7 @@ "password_login_enabled": true, "password_registration_enabled": true, "password_registration_email_required": true, + "password_registration_token_required": true, "registration_token_required": true, "email_change_allowed": true, "displayname_change_allowed": true, @@ -4685,7 +4686,8 @@ "human_name": "Google", "brand_name": "google", "created_at": "1970-01-01T00:00:00Z", - "disabled_at": null + "disabled_at": null, + "registration_token_required": false }, "links": { "self": "/api/admin/v1/upstream-oauth-providers/01040G2081040G2081040G2081" @@ -4704,7 +4706,8 @@ "human_name": "Apple ID", "brand_name": "apple", "created_at": "1970-01-01T00:00:00Z", - "disabled_at": "1970-01-01T00:00:00Z" + "disabled_at": "1970-01-01T00:00:00Z", + "registration_token_required": false }, "links": { "self": "/api/admin/v1/upstream-oauth-providers/02081040G2081040G2081040G2" @@ -4723,7 +4726,8 @@ "human_name": "Custom OAuth Provider", "brand_name": null, "created_at": "1970-01-01T00:00:00Z", - "disabled_at": null + "disabled_at": null, + "registration_token_required": true }, "links": { "self": "/api/admin/v1/upstream-oauth-providers/030C1G60R30C1G60R30C1G60R3" @@ -4784,7 +4788,8 @@ "human_name": "Google", "brand_name": "google", "created_at": "1970-01-01T00:00:00Z", - "disabled_at": null + "disabled_at": null, + "registration_token_required": false }, "links": { "self": "/api/admin/v1/upstream-oauth-providers/01040G2081040G2081040G2081" @@ -4859,10 +4864,14 @@ "description": "Whether a valid email address is required for password registrations.", "type": "boolean" }, - "registration_token_required": { - "description": "Whether registration tokens are required for password registrations.", + "password_registration_token_required": { "type": "boolean" }, + "registration_token_required": { + "description": "Whether registration tokens are required for password registrations.\n Deprecated in favor of `password_registration_token_required`", + "type": "boolean", + "deprecated": true + }, "email_change_allowed": { "description": "Whether users can change their email.", "type": "boolean" @@ -4900,6 +4909,7 @@ "password_login_enabled", "password_registration_enabled", "password_registration_email_required", + "password_registration_token_required", "registration_token_required", "email_change_allowed", "displayname_change_allowed", @@ -7382,10 +7392,15 @@ "null" ], "format": "date-time" + }, + "registration_token_required": { + "description": "Whether a registration token is required for registrations via this\n provider.", + "type": "boolean" } }, "required": [ - "created_at" + "created_at", + "registration_token_required" ] }, "SingleResponse_for_UpstreamOAuthProvider": { diff --git a/docs/config.schema.json b/docs/config.schema.json index 7cf6089b0..ead3d16d9 100644 --- a/docs/config.schema.json +++ b/docs/config.schema.json @@ -2338,6 +2338,11 @@ "$ref": "#/definitions/OnBackchannelLogout" } ] + }, + "registration_token_required": { + "description": "Whether or not to require a registration token on `OAuth2` auth\n\n Defaults to `false`", + "type": "boolean", + "default": false } }, "required": [ @@ -2807,6 +2812,10 @@ "description": "Whether email-based password recovery is enabled. Defaults to `false`.\n\n This has no effect if password login is disabled.", "type": "boolean" }, + "password_registration_token_required": { + "description": "Whether registration tokens are required for password registrations.\n Defaults to `false`.\n\n When enabled, users must provide a valid registration token during\n password registration. This has no effect if password registration\n is disabled.", + "type": "boolean" + }, "account_deactivation_allowed": { "description": "Whether users are allowed to delete their own account. Defaults to\n `true`.", "type": "boolean" @@ -2816,7 +2825,7 @@ "type": "boolean" }, "registration_token_required": { - "description": "Whether registration tokens are required for password registrations.\n Defaults to `false`.\n\n When enabled, users must provide a valid registration token during\n password registration. This has no effect if password registration\n is disabled.", + "description": "Whether registration tokens are required for password registrations\n This is deprecated in favor of `password_registration_token_required`", "type": "boolean" } }