Skip to main content

better_auth_api/plugins/passkey/
options.rs

1//! Application policies for WebAuthn ceremonies.
2
3use super::callbacks::{
4    PasskeyAuthenticationHook, PasskeyExtensionsResolver, PasskeyRegistrationHook,
5    PasskeyUserResolver,
6};
7use serde::{Deserialize, Serialize};
8use serde_json::{Map, Value};
9use std::sync::Arc;
10
11/// Explicit origins, or the request Origin header when no origin is configured.
12#[derive(Debug, Clone, Default)]
13pub enum PasskeyOrigins {
14    #[default]
15    Request,
16    Explicit(Vec<String>),
17}
18impl From<String> for PasskeyOrigins {
19    fn from(value: String) -> Self {
20        if value.is_empty() {
21            Self::Request
22        } else {
23            Self::Explicit(vec![value])
24        }
25    }
26}
27impl From<&str> for PasskeyOrigins {
28    fn from(value: &str) -> Self {
29        value.to_owned().into()
30    }
31}
32impl From<Vec<String>> for PasskeyOrigins {
33    fn from(value: Vec<String>) -> Self {
34        Self::Explicit(value)
35    }
36}
37
38/// Browser authenticator attachment preference.
39#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
40#[serde(rename_all = "kebab-case")]
41pub enum AuthenticatorAttachment {
42    Platform,
43    CrossPlatform,
44}
45/// Browser resident-key and user-verification preferences.
46#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
47#[serde(rename_all = "lowercase")]
48pub enum PasskeyRequirement {
49    Required,
50    Preferred,
51    Discouraged,
52}
53/// Registration options sent to the browser. Verification does not require UV.
54#[derive(Debug, Clone, Default, Serialize, Deserialize)]
55#[serde(rename_all = "camelCase")]
56pub struct AuthenticatorSelection {
57    #[serde(skip_serializing_if = "Option::is_none")]
58    pub authenticator_attachment: Option<AuthenticatorAttachment>,
59    #[serde(skip_serializing_if = "Option::is_none")]
60    pub resident_key: Option<PasskeyRequirement>,
61    #[serde(skip_serializing_if = "Option::is_none")]
62    pub require_resident_key: Option<bool>,
63    #[serde(skip_serializing_if = "Option::is_none")]
64    pub user_verification: Option<PasskeyRequirement>,
65}
66
67/// Static or request-dependent WebAuthn extension input.
68#[derive(Clone, Default)]
69pub enum PasskeyExtensions {
70    #[default]
71    None,
72    Static(Map<String, Value>),
73    Dynamic(Arc<dyn PasskeyExtensionsResolver>),
74}
75impl std::fmt::Debug for PasskeyExtensions {
76    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
77        match self {
78            Self::None => f.write_str("None"),
79            Self::Static(value) => f.debug_tuple("Static").field(value).finish(),
80            Self::Dynamic(_) => f.write_str("Dynamic(..)"),
81        }
82    }
83}
84/// Registration policy and callbacks.
85#[derive(Clone)]
86pub struct PasskeyRegistrationOptions {
87    pub require_session: bool,
88    pub resolve_user: Option<Arc<dyn PasskeyUserResolver>>,
89    pub after_verification: Option<Arc<dyn PasskeyRegistrationHook>>,
90    pub extensions: PasskeyExtensions,
91}
92impl Default for PasskeyRegistrationOptions {
93    fn default() -> Self {
94        Self {
95            require_session: true,
96            resolve_user: None,
97            after_verification: None,
98            extensions: PasskeyExtensions::None,
99        }
100    }
101}
102impl std::fmt::Debug for PasskeyRegistrationOptions {
103    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
104        f.debug_struct("PasskeyRegistrationOptions")
105            .field("require_session", &self.require_session)
106            .field("resolve_user", &self.resolve_user.is_some())
107            .field("after_verification", &self.after_verification.is_some())
108            .field("extensions", &self.extensions)
109            .finish()
110    }
111}
112/// Authentication policy and callback.
113#[derive(Clone, Default)]
114pub struct PasskeyAuthenticationOptions {
115    pub after_verification: Option<Arc<dyn PasskeyAuthenticationHook>>,
116    pub extensions: PasskeyExtensions,
117}
118impl std::fmt::Debug for PasskeyAuthenticationOptions {
119    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
120        f.debug_struct("PasskeyAuthenticationOptions")
121            .field("after_verification", &self.after_verification.is_some())
122            .field("extensions", &self.extensions)
123            .finish()
124    }
125}