Hex Version Docs

A security-focused WebAuthn server library for Elixir.

Alpha: The 0.x API can change, and the project has not completed its full WebAuthn conformance program. Review the validation status before production use.

ExSwan targets WebAuthn Level 2 and direct compatibility with @simplewebauthn/browser JSON. Its current compatibility evidence and intentional differences are recorded in docs/compatibility.md.

This package lives in the exswan monorepo. Related packages:

  • exswan — core WebAuthn library (this package)
  • exswan_plug — Plug integration helpers

Features

🔐 Covered WebAuthn Ceremonies

  • Registration and authentication ceremony support
  • ES256 credential support with none attestation
  • Layered security validation

🛡️ Security First

  • Cryptographic challenge generation
  • Origin and RP ID validation
  • Strict challenge, origin, RP ID, flags, and counter validation
  • Secure credential storage patterns

Developer Friendly

  • Clean, documented APIs
  • Comprehensive error handling
  • Unit, property, compatibility, and browser tests

Installation

Add exswan to your list of dependencies in mix.exs:

def deps do
  [
    {:exswan, "~> 0.1.0"}
  ]
end

Quick Start

1. Registration Flow

{:ok, %{options: options_json, ceremony: ceremony}} =
  ExSwan.generate_registration_options(
    rp_name: "Example Corp",
    rp_id: "example.com",
    user_name: "user@example.com",
    user_display_name: "John Doe",
    user_id: user_handle
  )

# Pass options_json directly to startRegistration({optionsJSON: options_json}).
{:ok, registration} =
  ExSwan.verify_registration_response(
    response: browser_response,
    expected_challenge: ceremony.challenge,
    expected_origin: "https://example.com",
    expected_rp_id: ceremony.rp_id
  )

2. Authentication Flow

{:ok, %{options: options_json, ceremony: ceremony}} =
  ExSwan.generate_authentication_options(
    rp_id: "example.com",
    allow_credentials: stored_credentials
  )

# Pass options_json directly to startAuthentication({optionsJSON: options_json}).
{:ok, authentication} =
  ExSwan.verify_authentication_response(
    response: browser_response,
    expected_challenge: ceremony.challenge,
    expected_origin: "https://example.com",
    expected_rp_id: ceremony.rp_id,
    credential: stored_credential
  )

Core Concepts

Credential Management

# Store the complete credential from registration.
credential = registration.credential

# Persist every authentication update atomically.
new_sign_count = authentication.new_sign_count
credential_backed_up = authentication.credential_backed_up

Security Considerations

  • Always validate origins against your allowlist
  • Use HTTPS in production environments
  • Implement proper credential storage with encryption
  • Regularly update dependencies for security patches
  • Consider implementing rate limiting for registration/authentication endpoints
  • Android SafetyNet attestation is intentionally unsupported because Google deprecated the service and its trust guarantees cannot be validated without the retired Google infrastructure. Android passkeys remain supported through none or another supported attestation format.

Documentation

License

ExSwan is available under the MIT License.