Skip to main content

openauth_passkey/
lib.rs

1//! Server-side passkey plugin for OpenAuth.
2//!
3//! The plugin is server-only. It exposes Better Auth-inspired HTTP endpoints
4//! under `/passkey/*`, contributes a `passkeys` table to the OpenAuth schema,
5//! and uses `webauthn-rs` for WebAuthn ceremony generation and verification.
6//!
7//! ```rust,no_run
8//! use openauth_core::options::OpenAuthOptions;
9//! use openauth_passkey::{passkey, PasskeyOptions};
10//!
11//! let options = OpenAuthOptions::new()
12//!     .secret("secret-a-at-least-32-chars-long!!")
13//!     .base_url("https://app.example.com")
14//!     .plugin(passkey(PasskeyOptions::default()));
15//! ```
16//!
17//! WebAuthn registration and authentication state is persisted server-side in
18//! OpenAuth's `verification` storage and keyed by a signed short-lived cookie.
19//! This is why the crate enables `webauthn-rs` state serialization: the state is
20//! not trusted from the client and is deleted after successful verification.
21
22mod challenge;
23mod cookies;
24mod errors;
25mod openapi;
26mod options;
27mod response;
28mod routes;
29mod schema;
30mod session;
31mod store;
32mod webauthn;
33
34pub use errors::PASSKEY_ERROR_CODES;
35pub use options::{
36    AfterAuthenticationVerificationInput, AfterRegistrationVerificationInput,
37    AuthenticatorAttachment, AuthenticatorSelection, PasskeyAdvancedOptions,
38    PasskeyAuthenticationOptions, PasskeyOptions, PasskeyRegistrationOptions,
39    PasskeyRegistrationUser, RegistrationWebAuthnOptions, ResidentKeyRequirement,
40    ResolveRegistrationUserInput, UserVerificationRequirement,
41};
42pub use store::Passkey;
43pub use webauthn::{
44    PasskeyAuthenticationStart, PasskeyRegistrationStart, PasskeyWebAuthnBackend,
45    VerifiedAuthentication, VerifiedPasskeyCredential, WebAuthnConfig,
46};
47
48use openauth_core::plugin::AuthPlugin;
49
50pub const UPSTREAM_PLUGIN_ID: &str = "passkey";
51
52/// Build the server-side passkey plugin.
53pub fn passkey(options: PasskeyOptions) -> AuthPlugin {
54    let options = std::sync::Arc::new(options);
55    let mut plugin = AuthPlugin::new(UPSTREAM_PLUGIN_ID).with_version(env!("CARGO_PKG_VERSION"));
56    for contribution in schema::contributions(&options.passkey_table) {
57        plugin = plugin.with_schema(contribution);
58    }
59    for code in errors::plugin_error_codes() {
60        plugin = plugin.with_error_code(code);
61    }
62    for endpoint in routes::endpoints(options) {
63        plugin = plugin.with_endpoint(endpoint);
64    }
65    plugin
66}