Skip to main content

alibi_api/plugins/passkey/
authentication.rs

1//! Trusted application policy after successful cryptographic authentication.
2use alibi_core::{AuthConfig, AuthRequest, AuthResult, ContextExtensions, utils::json::JsValue};
3use async_trait::async_trait;
4use std::sync::Arc;
5/// Verification authority: Core verifies supported typed keys; the bounded raw
6/// verifier verifies original COSE facts without manufacturing a Core result.
7#[derive(Debug, Clone)]
8pub enum AuthenticationResult {
9    Core(webauthn_rs::prelude::AuthenticationResult),
10    Raw(RawAuthenticationResult),
11}
12
13#[derive(Debug, Clone)]
14pub struct RawAuthenticationResult {
15    pub(super) credential_id: webauthn_rs::prelude::CredentialID,
16    pub(super) counter: u32,
17    pub(super) user_verified: bool,
18    pub(super) backup_eligible: bool,
19    pub(super) backup_state: bool,
20}
21
22impl AuthenticationResult {
23    pub fn cred_id(&self) -> &webauthn_rs::prelude::CredentialID {
24        match self {
25            Self::Core(result) => result.cred_id(),
26            Self::Raw(result) => &result.credential_id,
27        }
28    }
29    pub fn counter(&self) -> u32 {
30        match self {
31            Self::Core(result) => result.counter(),
32            Self::Raw(result) => result.counter,
33        }
34    }
35    pub fn user_verified(&self) -> bool {
36        match self {
37            Self::Core(result) => result.user_verified(),
38            Self::Raw(result) => result.user_verified,
39        }
40    }
41    pub fn backup_eligible(&self) -> bool {
42        match self {
43            Self::Core(result) => result.backup_eligible(),
44            Self::Raw(result) => result.backup_eligible,
45        }
46    }
47    pub fn backup_state(&self) -> bool {
48        match self {
49            Self::Core(result) => result.backup_state(),
50            Self::Raw(result) => result.backup_state,
51        }
52    }
53}
54
55/// Immutable request and application settings. Captures may hold typed services.
56pub struct PasskeyAuthenticationContext<'a> {
57    pub request: &'a AuthRequest,
58    pub auth_config: &'a AuthConfig,
59    pub extensions: &'a ContextExtensions,
60}
61
62impl std::fmt::Debug for PasskeyAuthenticationContext<'_> {
63    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64        f.debug_struct("PasskeyAuthenticationContext")
65            .finish_non_exhaustive()
66    }
67}
68
69/// Actual verifier result, supplied only after the signed assertion succeeds.
70#[derive(Debug, Clone)]
71pub struct VerifiedPasskeyAuthentication {
72    pub result: AuthenticationResult,
73    pub origin: String,
74    pub rp_id: String,
75}
76
77/// Awaited before counter persistence and session creation. The client data is
78/// untrusted application input; it cannot replace the verified credential owner.
79#[async_trait]
80pub trait PasskeyAuthenticationAfterVerification: Send + Sync {
81    async fn after_verification(
82        &self,
83        context: &PasskeyAuthenticationContext<'_>,
84        verification: &VerifiedPasskeyAuthentication,
85        client_data: &JsValue,
86    ) -> AuthResult<()>;
87}
88
89#[derive(Clone, Default)]
90pub struct PasskeyAuthenticationConfig {
91    pub after_verification: Option<Arc<dyn PasskeyAuthenticationAfterVerification>>,
92}
93impl std::fmt::Debug for PasskeyAuthenticationConfig {
94    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
95        f.debug_struct("PasskeyAuthenticationConfig")
96            .field("after_verification", &self.after_verification.is_some())
97            .finish()
98    }
99}