ExSwan
A security-focused WebAuthn server library for Elixir.
Alpha: The
0.xAPI 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
noneattestation - 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
noneor another supported attestation format.
Documentation
License
ExSwan is available under the MIT License.