Files
T

6.3 KiB

API Reference: FIDO2/WebAuthn Hardware Security Key Authentication Server

Overview

Implements a complete WebAuthn relying party server with registration/authentication ceremonies, YubiKey enrollment, credential management, recovery codes, and audit logging. Built on python-fido2 and Flask, supporting both roaming authenticators (USB/NFC security keys) and platform authenticators (Windows Hello, Touch ID).

Dependencies

Package Version Purpose
fido2 >=2.0.0 Yubico's python-fido2 library for WebAuthn relying party operations
flask >=2.3 HTTP server framework for API endpoints and session management
cryptography >=41.0 Cryptographic primitives used by python-fido2

Install with: pip install fido2 flask cryptography

CLI Usage

# Development server on localhost (no TLS needed)
python agent.py --rp-id localhost --rp-name "My App" --port 5000

# Production with strict security settings
python agent.py --rp-id auth.example.com --rp-name "Example Corp" \
    --user-verification required --attestation direct --db prod_keys.db

# Verbose logging for debugging
python agent.py --rp-id localhost --rp-name "Test" -v

Arguments

Argument Required Description
--rp-id No Relying Party ID -- must match the application domain (default: localhost)
--rp-name No Relying Party display name shown in authenticator prompts (default: FIDO2 Demo)
--host No Server bind address (default: localhost)
--port No Server port (default: 5000)
--db No SQLite database path for credentials and users (default: webauthn.db)
--attestation No Attestation preference: none, indirect, direct, enterprise (default: none)
--user-verification No UV requirement: required, preferred, discouraged (default: preferred)
-v, --verbose No Enable debug logging

API Endpoints

Registration

POST /api/register/begin

Start the WebAuthn registration ceremony.

Request body:

{
  "username": "alice",
  "display_name": "Alice Smith",
  "resident_key": true
}

Response: PublicKeyCredentialCreationOptions (JSON-serialized)

POST /api/register/complete

Complete registration with the authenticator's response.

Request body: Serialized PublicKeyCredential from navigator.credentials.create()

Response:

{
  "status": "OK",
  "recovery_codes": ["A1B2C3D4", "E5F6G7H8", ...],
  "message": "Save these recovery codes securely."
}

Authentication

POST /api/authenticate/begin

Start the WebAuthn authentication ceremony.

Request body:

{
  "username": "alice"
}

Omit username for discoverable credential (passwordless) flow.

Response: PublicKeyCredentialRequestOptions (JSON-serialized)

POST /api/authenticate/complete

Complete authentication with the authenticator's assertion.

Request body: Serialized PublicKeyCredential from navigator.credentials.get()

Response:

{
  "status": "OK",
  "username": "alice"
}

Key Management

GET /api/keys

List all registered security keys for the authenticated user.

POST /api/keys/<id>/revoke

Revoke a security key. Requires at least one remaining active credential.

PUT /api/keys/<id>/label

Update a key's display label.

Recovery

POST /api/recover

Authenticate using a recovery code when all keys are unavailable.

Request body:

{
  "username": "alice",
  "recovery_code": "A1B2C3D4"
}

Admin

GET /api/admin/stats

Deployment statistics: total users, credentials, backup key adoption, authentication metrics.

GET /api/admin/audit-log?limit=100

Authentication event audit trail with timestamps, usernames, event types, and IP addresses.

Key Functions

User Management

create_user(conn, username, display_name)

Creates a user with a cryptographically random 32-byte user handle.

get_user_by_username(conn, username) / get_user_by_handle(conn, user_handle)

User lookups by username (standard flow) or user handle (discoverable credential flow).

Credential Management

store_credential(conn, user_id, credential_id, public_key, sign_count, ...)

Persists a WebAuthn credential with AAGUID, label, transport hints, and discoverable flag.

get_user_credentials(conn, user_id)

Retrieves all active (non-revoked) credentials for a user.

revoke_credential(conn, credential_db_id, user_id)

Soft-revokes a credential. Prevents revocation of the last remaining credential.

update_sign_count(conn, credential_id, new_count)

Updates sign count and last-used timestamp after successful authentication. Sign count regression is logged as a security event (possible cloned key).

Recovery

generate_recovery_codes(conn, user_id, count=8)

Generates 8 one-time recovery codes (stored as SHA-256 hashes). Previous codes are invalidated.

verify_recovery_code(conn, user_id, code)

Verifies and consumes a recovery code (single-use).

Helpers

build_credential_descriptors(creds)

Converts stored credentials to PublicKeyCredentialDescriptor list for WebAuthn ceremonies.

reconstruct_credential_data(creds)

Rebuilds AttestedCredentialData objects from database records for python-fido2 verification.

Database Schema

Table Purpose
users User accounts with random user handles, usernames, and passkey-only flag
credentials WebAuthn credentials with public keys, sign counts, AAGUIDs, and revocation status
auth_events Audit log of all registration, authentication, revocation, and recovery events
recovery_codes Hashed one-time recovery codes with usage tracking

Security Features

Feature Implementation
Phishing resistance Origin binding via WebAuthn RP ID verification
Clone detection Sign count validation with regression warnings
Recovery codes SHA-256 hashed, single-use, auto-invalidated on regeneration
Session security Secure, HttpOnly, SameSite=Strict cookies
Key revocation Soft delete with minimum-one-key enforcement
Audit trail All auth events logged with IP, user agent, and timestamp
Attestation verification Configurable attestation preference for enterprise key verification