alibi_plugins/passkey/
options.rs1use alibi_core::{AuthConfig, AuthRequest, AuthResult, ContextExtensions, wire::UserView};
3use async_trait::async_trait;
4use serde_json::Value;
5use std::sync::Arc;
6
7pub struct PasskeyOptionsContext<'a> {
8 pub request: Option<&'a AuthRequest>,
10 pub endpoint: Option<&'a alibi_core::endpoint::EndpointCall>,
12 pub auth_config: &'a AuthConfig,
13 pub extensions: &'a ContextExtensions,
14 pub user: Option<&'a UserView>,
15}
16
17#[async_trait]
18pub trait PasskeyExtensionsResolver: Send + Sync {
19 async fn resolve(&self, context: &PasskeyOptionsContext<'_>) -> AuthResult<Value>;
20}
21
22#[derive(Clone)]
23pub enum PasskeyExtensions {
24 Static(Value),
25 Resolver(Arc<dyn PasskeyExtensionsResolver>),
26}
27impl std::fmt::Debug for PasskeyExtensions {
28 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29 match self {
30 Self::Static(value) => f.debug_tuple("Static").field(value).finish(),
31 Self::Resolver(_) => f.write_str("Resolver(..)"),
32 }
33 }
34}
35impl PasskeyExtensions {
36 pub(super) async fn resolve(&self, context: &PasskeyOptionsContext<'_>) -> AuthResult<Value> {
37 let value = match self {
38 Self::Static(value) => Ok(value.clone()),
39 Self::Resolver(resolver) => resolver.resolve(context).await.map_err(|error| {
40 if alibi_core::endpoint::is_endpoint_api_error(&error) {
41 error
42 } else {
43 alibi_core::AuthError::CallbackFailure(Box::new(error))
44 }
45 }),
46 }?;
47 if !value.is_object() {
48 return Err(alibi_core::AuthError::config(
49 "Passkey extensions must be an object",
50 ));
51 }
52 Ok(value)
53 }
54}
55
56#[derive(Debug, Clone, Default)]
57pub struct PasskeyAuthenticatorSelection {
58 pub resident_key: Option<String>,
59 pub user_verification: Option<String>,
60 pub authenticator_attachment: Option<String>,
61}