Skip to content
gblachPublic

About

A simple and secure WebAuthn/Passkey implementation for Rust.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

Β 

History

93 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Passki

A simple and secure WebAuthn/Passkey implementation for Rust.

Crates.io Documentation License

Features

  • ✨ Simple API - Easy-to-use interface for passkey registration and authentication
  • πŸ” Multiple Algorithms - Support for EdDSA (Ed25519), ES256/ES384 (P-256/P-384), and RS256/RS384 (RSA)
  • πŸ›‘οΈ Security First - Built-in replay attack protection via signature counters
  • πŸ“¦ Framework Agnostic - No web framework lock-in, works with any HTTP server
  • πŸ“¨ Spec JSON Shapes - Both ceremonies take credential.toJSON() as the browser produces it, so the front end remaps nothing
  • πŸ”‘ Extensions - Support for credProps (discoverable credential reporting), PRF (key derivation / E2E encryption), largeBlob (blob storage on the authenticator), credProtect (user verification policy on security keys) and minPinLength (PIN policy on managed keys)
  • πŸ’‘ Hints - Steer the browser's UI toward a security key, this device or a phone, without ruling any of them out
  • 🌐 Related Origins - One passkey across several domains, with a helper for the .well-known/webauthn file
  • πŸ–ΌοΈ Cross-origin Iframes - Refused by default, with an opt-in allowlist of embedding origins checked against topOrigin
  • πŸ“‘ Signal API - Payloads that tell the browser when a passkey or a username changed, so stale ones stop being offered
  • πŸ“œ Attestation - Statement verification for packed, tpm, android-key and fido-u2f, with opt-in trust path validation against your own roots
  • πŸ¦€ Three Crypto Backends - Pure Rust RustCrypto by default, aws-lc-rs with the aws-lc-rs feature or graviola with the graviola feature (see Installation); passki itself contains no unsafe code

Installation

Add this to your Cargo.toml:

[dependencies]
passki = "0.5"

Signatures are verified with the pure Rust RustCrypto crates by default, which need no C toolchain. To use aws-lc-rs instead, which is 3-5x faster at ECDSA and RSA and has a FIPS-validated build, enable its feature:

[dependencies]
passki = { version = "0.5", default-features = false, features = ["aws-lc-rs"] }

graviola is nearly as fast as aws-lc-rs and, like RustCrypto, needs no C toolchain, but builds only for x86_64 and aarch64:

[dependencies]
passki = { version = "0.5", default-features = false, features = ["graviola"] }
Feature Default Backend
rust-crypto yes p256, p384, ed25519-dalek and rsa
aws-lc-rs no aws-lc-rs
graviola no graviola

If several are enabled, aws-lc-rs wins over graviola, and both win over RustCrypto. The other backends are still compiled in that case, so turn off the default features to drop them.

Quick Start

use passki::{AuthenticationOptions, Passki, RegistrationOptions, StoredPasskey};

let passki = Passki::new(
    "example.com",              // relying party ID (the domain)
    &["https://example.com"],   // accepted origins
    "Example Corp"              // name shown in the browser prompt
);

// Registration step 1: issue a challenge
let user_id = b"unique_user_identifier_12345"; // at least 16 bytes
let (registration_challenge, registration_state) = passki.start_passkey_registration(
    user_id,
    "alice@example.com",            // username
    "Alice Smith",                  // display name
    RegistrationOptions::default(),
).expect("user_id must be at least 16 bytes");

// Send registration_challenge to the client as JSON, keep registration_state.

// Registration step 2: verify the credential the client created
let mut stored_passkey = passki.finish_passkey_registration(
    &registration_credential,
    &registration_state,
)?;

// Save stored_passkey in your database, associated with the user.

// Authentication step 1: issue a challenge
let (authentication_challenge, authentication_state) = passki.start_passkey_authentication(
    &user_passkeys,
    AuthenticationOptions::default(),
)?;

// Authentication step 2: verify the signature
let result = passki.finish_passkey_authentication(
    &authentication_credential,
    &authentication_state,
    &stored_passkey,
)?;

// Persist the new counter, or replay detection has nothing to compare against.
stored_passkey.counter = result.counter;

Security Considerations

  • πŸ”’ Always use HTTPS in production - browsers refuse WebAuthn on insecure origins
  • πŸ”„ Store the counter returned by each authentication, or cloned authenticators go undetected
  • πŸ” Require user verification for sensitive operations
  • ⏱️ Keep ceremony timeouts short; the state stored between the two steps expires with them
  • πŸ–ΌοΈ Allow only the iframe embedders you trust with with_embedding_origins

Requirements

  • Rust 1.85 or later (Edition 2024)

Examples

The examples/ directory has complete registration and authentication flows for several web frameworks: Actix-web | Axum | Poem | Rocket | Salvo | Warp

Each one also demonstrates credProps, PRF key derivation and the Signal API.

cargo run --example axum  # or actix-web, poem, rocket, salvo, warp

Then visit http://localhost:3000 in your browser.

WebAuthn Specification Levels

WebAuthn has three specification levels published by the W3C, plus extensions that other specifications define. Checkboxes mark features currently implemented in passki.

Level 1 (2019)

The initial recommendation. Defined the core protocol:

  • Registration ceremony (create) and authentication ceremony (get)
  • Challenge generation and binding
  • Client data JSON origin verification
  • Authenticator data parsing
  • COSE public key extraction
  • Signature verification (EdDSA/Ed25519, ES256/P-256, ES384/P-384, RS256, RS384)
  • Signature counter tracking and replay detection
  • Credential exclusion (excludeCredentials)
  • AttestationConveyancePreference (none / indirect / direct)
  • Attestation object CBOR parsing
  • Attestation statement verification (packed, tpm, android-key, fido-u2f)
  • rpId hash verification in authenticator data
  • UP (user present) flag enforcement
  • UV (user verified) flag enforcement
  • AAGUID exposure
  • authenticatorAttachment (platform / cross-platform)
  • Attestation trust path validation

Level 2 (2021)

A substantial expansion, still the most widely implemented level today:

  • Discoverable credentials / usernameless flows (empty allowCredentials)
  • ResidentKeyRequirement (discouraged / preferred / required)
  • enterprise attestation conveyance preference
  • Zero-counter authenticator support
  • credProps extension
  • largeBlob extension
  • userHandle in authentication response
  • transports on credential descriptors

Level 3 (2026)

A W3C Recommendation since 25 August 2026, though browser support for its newer parts is still filling in:

  • PRF extension (prf)
  • BE/BS flags (backup eligibility/state)
  • Related origin requests
  • RegistrationResponseJSON and AuthenticationResponseJSON request shapes
  • Signal API
  • hints (security-key / client-device / hybrid)
  • attestationFormats
  • evalByCredential in the prf extension
  • compound attestation statement format
  • Cross-origin ceremonies in iframes, verifying topOrigin

Defined outside WebAuthn

These extensions are registered in the IANA WebAuthn extension identifiers registry but specified elsewhere, so they are not tied to a WebAuthn level:

License

This project is licensed under the Apache License, Version 2.0 (LICENSE).

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

About

A simple and secure WebAuthn/Passkey implementation for Rust.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages