Skip to content

Commit 8714ddb

Browse files
committed
Experimental configuration toggle for passkeys
1 parent 5a1ac37 commit 8714ddb

File tree

18 files changed

+81
-22
lines changed

18 files changed

+81
-22
lines changed

crates/cli/src/util.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ pub fn site_config_from_config(
214214
captcha,
215215
minimum_password_complexity: password_config.minimum_complexity(),
216216
session_expiration,
217+
passkeys_enabled: experimental_config.passkeys,
217218
})
218219
}
219220

crates/config/src/sections/experimental.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,12 @@ pub struct ExperimentalConfig {
7575
/// Disabled by default
7676
#[serde(skip_serializing_if = "Option::is_none")]
7777
pub inactive_session_expiration: Option<InactiveSessionExpirationConfig>,
78+
79+
/// Experimental passkey support
80+
///
81+
/// Disabled by default
82+
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
83+
pub passkeys: bool,
7884
}
7985

8086
impl Default for ExperimentalConfig {
@@ -83,6 +89,7 @@ impl Default for ExperimentalConfig {
8389
access_token_ttl: default_token_ttl(),
8490
compat_token_ttl: default_token_ttl(),
8591
inactive_session_expiration: None,
92+
passkeys: false,
8693
}
8794
}
8895
}
@@ -92,6 +99,7 @@ impl ExperimentalConfig {
9299
is_default_token_ttl(&self.access_token_ttl)
93100
&& is_default_token_ttl(&self.compat_token_ttl)
94101
&& self.inactive_session_expiration.is_none()
102+
&& !self.passkeys
95103
}
96104
}
97105

crates/data-model/src/site_config.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,4 +87,7 @@ pub struct SiteConfig {
8787
pub minimum_password_complexity: u8,
8888

8989
pub session_expiration: Option<SessionExpirationConfig>,
90+
91+
/// Whether passkeys are enabled
92+
pub passkeys_enabled: bool,
9093
}

crates/handlers/src/graphql/model/site_config.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ pub struct SiteConfig {
5353
/// The exact scorer (including dictionaries and other data tables)
5454
/// in use is <https://crates.io/crates/zxcvbn>.
5555
minimum_password_complexity: u8,
56+
57+
/// Whether passkeys are enabled
58+
passkeys_enabled: bool,
5659
}
5760

5861
#[derive(SimpleObject)]
@@ -98,6 +101,7 @@ impl SiteConfig {
98101
password_registration_enabled: data_model.password_registration_enabled,
99102
account_deactivation_allowed: data_model.account_deactivation_allowed,
100103
minimum_password_complexity: data_model.minimum_password_complexity,
104+
passkeys_enabled: data_model.passkeys_enabled,
101105
}
102106
}
103107
}

crates/handlers/src/test_utils.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ pub fn test_site_config() -> SiteConfig {
141141
captcha: None,
142142
minimum_password_complexity: 1,
143143
session_expiration: None,
144+
passkeys_enabled: false,
144145
}
145146
}
146147

crates/handlers/src/views/login.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,10 @@ pub(crate) async fn get(
8989

9090
let providers = repo.upstream_oauth_provider().all_enabled().await?;
9191

92-
// If password-based login is disabled, and there is only one upstream provider,
92+
// If password-based login and passkeys are disabled, and there is only one upstream provider,
9393
// we can directly start an authorization flow
94-
if !site_config.password_login_enabled && providers.len() == 1 {
94+
if !site_config.password_login_enabled && !site_config.passkeys_enabled && providers.len() == 1
95+
{
9596
let provider = providers.into_iter().next().unwrap();
9697

9798
let mut destination = UpstreamOAuth2Authorize::new(provider.id);

crates/templates/src/context/ext.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ impl SiteConfigExt for SiteConfig {
4747
password_registration: self.password_registration_enabled,
4848
password_login: self.password_login_enabled,
4949
account_recovery: self.account_recovery_allowed,
50+
passkeys_enabled: self.passkeys_enabled,
5051
}
5152
}
5253
}

crates/templates/src/context/features.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use minijinja::{
1313

1414
/// Site features information.
1515
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16+
#[allow(clippy::struct_excessive_bools)]
1617
pub struct SiteFeatures {
1718
/// Whether local password-based registration is enabled.
1819
pub password_registration: bool,
@@ -22,6 +23,9 @@ pub struct SiteFeatures {
2223

2324
/// Whether email-based account recovery is enabled.
2425
pub account_recovery: bool,
26+
27+
/// Whether passkeys are enabled
28+
pub passkeys_enabled: bool,
2529
}
2630

2731
impl Object for SiteFeatures {
@@ -30,6 +34,7 @@ impl Object for SiteFeatures {
3034
"password_registration" => Some(Value::from(self.password_registration)),
3135
"password_login" => Some(Value::from(self.password_login)),
3236
"account_recovery" => Some(Value::from(self.account_recovery)),
37+
"passkeys_enabled" => Some(Value::from(self.passkeys_enabled)),
3338
_ => None,
3439
}
3540
}
@@ -39,6 +44,7 @@ impl Object for SiteFeatures {
3944
"password_registration",
4045
"password_login",
4146
"account_recovery",
47+
"passkeys_enabled",
4248
])
4349
}
4450
}

crates/templates/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,7 @@ mod tests {
487487
password_login: true,
488488
password_registration: true,
489489
account_recovery: true,
490+
passkeys_enabled: true,
490491
};
491492
let vite_manifest_path =
492493
Utf8Path::new(env!("CARGO_MANIFEST_DIR")).join("../../frontend/dist/manifest.json");

docs/config.schema.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2495,6 +2495,10 @@
24952495
"$ref": "#/definitions/InactiveSessionExpirationConfig"
24962496
}
24972497
]
2498+
},
2499+
"passkeys": {
2500+
"description": "Experimental passkey support\n\nDisabled by default",
2501+
"type": "boolean"
24982502
}
24992503
}
25002504
},

0 commit comments

Comments
 (0)