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

84 Commits

Folders and files

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
  • 🦀 Pure Rust - Memory-safe implementation with no unsafe code

Installation

Add this to your Cargo.toml:

[dependencies]
passki = "0.4"

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 | Warp

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

cargo run --example axum  # or actix-web, poem, rocket, 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