Skip to content

Simple Authentication Flows

Rain Zhang edited this page Nov 6, 2025 · 2 revisions

Simple Authentication Flows

Table of Contents

  1. Introduction
  2. System Architecture
  3. Authentication Flow Overview
  4. Endpoint Specifications
  5. Challenge Generation and Verification
  6. Credential Registration Process
  7. Authentication Process
  8. Session Management
  9. Error Handling and Validation
  10. Performance Considerations
  11. Security Implementation
  12. Troubleshooting Guide

Introduction

The simple authentication flows provide a streamlined implementation of WebAuthn authentication using the /register/begin, /register/complete, /authenticate/begin, and /authenticate/complete endpoints. These flows are designed for simplicity while maintaining strong security standards, supporting both classical and post-quantum cryptographic algorithms.

The implementation leverages the FIDO2 server library to handle the core WebAuthn protocol logic, including challenge generation, credential verification, and attestation validation. The system supports multiple cryptographic algorithms including ML-DSA variants for post-quantum security.

System Architecture

The simple authentication system follows a layered architecture with clear separation of concerns:

graph TB
subgraph "Client Layer"
Browser[Browser]
JS[auth-simple.js]
end
subgraph "Server Layer"
Flask[Flask Application]
Routes[simple.py Routes]
Config[Configuration]
end
subgraph "FIDO2 Layer"
FidoServer[FIDO2 Server]
Crypto[Cryptography Library]
end
subgraph "Storage Layer"
Memory[Session Storage]
Cloud[Cloud Storage]
end
Browser --> JS
JS --> Flask
Flask --> Routes
Routes --> FidoServer
FidoServer --> Crypto
Routes --> Memory
Routes --> Cloud
Loading

Diagram sources

  • app.py
  • simple.py
  • config.py

Section sources

  • app.py
  • config.py

Authentication Flow Overview

The simple authentication system implements two primary flows: credential registration and authentication. Both flows utilize stateless challenge validation with session-based state management.

sequenceDiagram
participant Client as Client Browser
participant Server as Simple Server
participant Fido2 as FIDO2 Server
participant Storage as Credential Storage
Note over Client,Storage : Registration Flow
Client->>Server : POST /register/begin
Server->>Fido2 : register_begin()
Fido2-->>Server : Challenge + State
Server-->>Client : Registration Options
Client->>Client : Generate Credential
Client->>Server : POST /register/complete
Server->>Fido2 : register_complete()
Fido2->>Fido2 : Verify Attestation
Fido2-->>Server : Auth Data
Server->>Storage : Store Credential
Server-->>Client : Registration Success
Note over Client,Storage : Authentication Flow
Client->>Server : POST /authenticate/begin
Server->>Storage : Load Credentials
Server->>Fido2 : authenticate_begin()
Fido2-->>Server : Challenge + State
Server-->>Client : Authentication Options
Client->>Client : Sign Assertion
Client->>Server : POST /authenticate/complete
Server->>Fido2 : authenticate_complete()
Fido2->>Fido2 : Verify Signature
Fido2-->>Server : Matched Credential
Server-->>Client : Authentication Success
Loading

Diagram sources

  • simple.py
  • simple.py
  • auth-simple.js
  • auth-simple.js

Endpoint Specifications

Register Begin Endpoint

Endpoint: POST /api/register/begin?email={email}

Purpose: Initiates the credential registration process by generating challenge options for the client.

Request Schema:

{
  "credentials": [
    {
      "credentialId": "base64_encoded_string",
      "aaguid": "base64_encoded_string",
      "publicKey": "base64_encoded_string",
      "algorithm": -50
    }
  ]
}

Response Schema:

{
  "publicKey": {
    "challenge": "base64_url_encoded_string",
    "rp": {
      "id": "relying-party-id",
      "name": "Relying Party Name"
    },
    "user": {
      "id": "base64_url_encoded_string",
      "name": "username",
      "displayName": "Display Name"
    },
    "pubKeyCredParams": [
      {
        "type": "public-key",
        "alg": -50
      }
    ],
    "timeout": 90000,
    "attestation": "none",
    "authenticatorSelection": {
      "authenticatorAttachment": "cross-platform",
      "requireResidentKey": false,
      "userVerification": "discouraged"
    }
  },
  "__session_state": "base64_url_encoded_string"
}

HTTP Methods: POST

Authentication: None required

Section sources

  • simple.py

Register Complete Endpoint

Endpoint: POST /api/register/complete?email={email}

Purpose: Completes the credential registration process by verifying the client's response and storing the credential.

Request Schema:

{
  "id": "base64_url_encoded_string",
  "rawId": "base64_url_encoded_string",
  "response": {
    "attestationObject": "base64_url_encoded_string",
    "clientDataJSON": "base64_url_encoded_string"
  },
  "type": "public-key",
  "__session_state": "base64_url_encoded_string"
}

Response Schema:

{
  "status": "OK",
  "algo": "ML-DSA-87 (PQC)",
  "storedCredential": {
    "credentialId": "base64_encoded_string",
    "email": "user@example.com",
    "userName": "username",
    "displayName": "Display Name",
    "publicKey": "base64_encoded_string",
    "algorithm": -50,
    "signCount": 0,
    "createdAt": 1640995200.0
  },
  "relyingParty": {
    "attestationFmt": "packed",
    "credentialId": "hex_string",
    "rpIdHash": "hex_string",
    "authenticatorDataHash": "hex_string"
  }
}

HTTP Methods: POST

Authentication: None required

Section sources

  • simple.py

Authenticate Begin Endpoint

Endpoint: POST /api/authenticate/begin?email={email}

Purpose: Initiates the authentication process by loading stored credentials and generating challenge options.

Request Schema:

{
  "credentials": [
    {
      "credentialId": "base64_encoded_string",
      "aaguid": "base64_encoded_string",
      "publicKey": "base64_encoded_string"
    }
  ]
}

Response Schema:

{
  "publicKey": {
    "challenge": "base64_url_encoded_string",
    "rpId": "relying-party-id",
    "allowCredentials": [
      {
        "id": "base64_url_encoded_string",
        "type": "public-key"
      }
    ],
    "timeout": 90000,
    "userVerification": "discouraged"
  },
  "__session_state": "base64_url_encoded_string"
}

HTTP Methods: POST

Authentication: None required

Section sources

  • simple.py

Authenticate Complete Endpoint

Endpoint: POST /api/authenticate/complete?email={email}

Purpose: Completes the authentication process by verifying the client's signature against the stored credential.

Request Schema:

{
  "id": "base64_url_encoded_string",
  "rawId": "base64_url_encoded_string",
  "response": {
    "authenticatorData": "base64_url_encoded_string",
    "clientDataJSON": "base64_url_encoded_string",
    "signature": "base64_url_encoded_string",
    "userHandle": "base64_url_encoded_string"
  },
  "type": "public-key",
  "__session_state": "base64_url_encoded_string"
}

Response Schema:

{
  "status": "OK",
  "authenticatedCredentialId": "base64_url_encoded_string",
  "signCount": 123
}

HTTP Methods: POST

Authentication: None required

Section sources

  • simple.py

Challenge Generation and Verification

Challenge Creation Process

The challenge generation process ensures cryptographic randomness and proper validation:

flowchart TD
Start([Begin Registration]) --> GenChallenge["Generate Random Challenge<br/>32 bytes minimum"]
GenChallenge --> ValidateChallenge{"Challenge Length >= 16 bytes?"}
ValidateChallenge --> |No| ThrowError["Throw ValueError"]
ValidateChallenge --> |Yes| CreateState["Create Internal State<br/>Store challenge + UV"]
CreateState --> BuildOptions["Build Credential Creation Options"]
BuildOptions --> SerializeJSON["Serialize to JSON<br/>with Session State"]
SerializeJSON --> SendToClient["Send to Client"]
Start2([Begin Authentication]) --> GenChallenge2["Generate Random Challenge<br/>32 bytes minimum"]
GenChallenge2 --> ValidateChallenge2{"Challenge Length >= 16 bytes?"}
ValidateChallenge2 --> |No| ThrowError2["Throw ValueError"]
ValidateChallenge2 --> |Yes| CreateState2["Create Internal State<br/>Store challenge + UV"]
CreateState2 --> BuildOptions2["Build Credential Request Options"]
BuildOptions2 --> SerializeJSON2["Serialize to JSON<br/>with Session State"]
SerializeJSON2 --> SendToClient2["Send to Client"]
Loading

Diagram sources

  • server.py
  • simple.py

Challenge Verification Logic

The challenge verification process ensures that the client's response matches the originally issued challenge:

Verification Step Purpose Implementation
Challenge Comparison Verify client sent correct challenge Constant-time comparison using constant_time.bytes_eq()
Origin Validation Ensure request comes from authorized origin verify_origin() function checks RP ID against origin
RP ID Hash Validation Confirm authenticator data matches RP ID Compare auth_data.rp_id_hash with expected hash
User Presence Flag Verify user interaction occurred Check auth_data.is_user_present()
User Verification Enforce user verification requirement Validate UV flag against state requirement

Section sources

  • server.py
  • server.py

Credential Registration Process

Registration Flow Architecture

The registration process involves multiple stages of validation and attestation:

sequenceDiagram
participant Client as Client
participant Server as Simple Server
participant Fido2 as FIDO2 Server
participant Attestation as Attestation Verifier
participant Storage as Storage
Client->>Server : POST /register/begin
Server->>Server : Parse existing credentials
Server->>Fido2 : register_begin()
Fido2-->>Server : Challenge + State
Server-->>Client : Registration Options
Client->>Client : Generate credential
Client->>Server : POST /register/complete
Server->>Server : Extract attestation details
Server->>Server : Validate session state
Server->>Fido2 : register_complete()
Fido2->>Attestation : Verify attestation
Attestation-->>Fido2 : Validation result
Fido2-->>Server : Authenticator data
Server->>Storage : Store credential
Server-->>Client : Registration success
Loading

Diagram sources

  • simple.py
  • simple.py

Attestation Verification

The system performs comprehensive attestation verification:

Verification Type Description Validation Method
Signature Validity Verify attestation signature Cryptographic signature verification
Root Certificate Validity Check certificate chain Trust anchor validation
RP ID Hash Verify relying party ID SHA-256 hash comparison
AAGUID Matching Validate authenticator ID Authenticator-specific validation
Metadata Checks Verify device metadata MDS3 metadata validation

Section sources

  • simple.py

Public Key Material Processing

The system handles various public key formats and algorithms:

flowchart TD
ParseKey["Parse Public Key"] --> CheckFormat{"Key Format?"}
CheckFormat --> |COSE| DecodeCOSE["Decode COSE Format"]
CheckFormat --> |Base64| DecodeBase64["Decode Base64"]
CheckFormat --> |Hex| DecodeHex["Decode Hex"]
DecodeCOSE --> ValidateKey["Validate Key Parameters"]
DecodeBase64 --> ValidateKey
DecodeHex --> ValidateKey
ValidateKey --> CheckAlgorithm{"Algorithm Supported?"}
CheckAlgorithm --> |Yes| StoreKey["Store Public Key"]
CheckAlgorithm --> |No| RejectKey["Reject Unsupported Algorithm"]
StoreKey --> AddMaterial["Add to Public Key Material"]
AddMaterial --> Complete["Registration Complete"]
Loading

Diagram sources

  • simple.py

Section sources

  • simple.py

Authentication Process

Authentication Flow Implementation

The authentication process validates client signatures against stored credentials:

sequenceDiagram
participant Client as Client
participant Server as Simple Server
participant Fido2 as FIDO2 Server
participant Crypto as Cryptography
Client->>Server : POST /authenticate/begin
Server->>Server : Load stored credentials
Server->>Fido2 : authenticate_begin()
Fido2-->>Server : Challenge + State
Server-->>Client : Authentication options
Client->>Client : Sign assertion
Client->>Server : POST /authenticate/complete
Server->>Server : Validate session state
Server->>Fido2 : authenticate_complete()
Fido2->>Crypto : Verify signature
Crypto-->>Fido2 : Verification result
Fido2-->>Server : Matched credential
Server-->>Client : Authentication success
Loading

Diagram sources

  • simple.py
  • server.py

Signature Verification Process

The signature verification process ensures cryptographic authenticity:

Step Operation Security Check
Credential Lookup Find matching credential ID O(n) linear search through stored credentials
Data Concatenation Combine authenticator data + client hash Prepare signed data for verification
Signature Verification Verify against public key Cryptographic signature validation
Counter Validation Check signature counter Prevent replay attacks
Flag Validation Verify authenticator flags Ensure proper authenticator state

Section sources

  • server.py

Session Management

State Persistence Strategy

The simple authentication system uses Flask sessions for state management:

graph LR
subgraph "Session Storage"
State["Session State<br/>Challenge + UV"]
Credentials["Simple Credentials<br/>Stored in Session"]
RP["RP ID<br/>Registration/Auth"]
end
subgraph "Request Flow"
Begin["Begin Request"] --> Store["Store in Session"]
Complete["Complete Request"] --> Retrieve["Retrieve from Session"]
Retrieve --> Validate["Validate State"]
Validate --> Clear["Clear Session"]
end
Store --> State
Store --> Credentials
Store --> RP
State --> Begin
Credentials --> Begin
RP --> Begin
Loading

Diagram sources

  • simple.py
  • simple.py

Session Security Measures

Security Feature Implementation Purpose
Session Expiration Flask default session timeout Prevent stale state attacks
State Binding Challenge + UV in state Bind state to specific request
Session Isolation Separate registration/auth states Prevent cross-session attacks
Secure Cookies HTTPS-only session cookies Protect session data

Section sources

  • simple.py
  • simple.py

Error Handling and Validation

Common Error Scenarios

The system handles various error conditions with appropriate responses:

Error Type Cause HTTP Status Response
Invalid Challenge Mismatched challenge 400 "Wrong challenge in response"
Expired State Stale session state 400 "State not found or expired"
Invalid Signature Malformed signature 400 "Invalid signature"
Unknown Credential Non-existent credential ID 400 "Unknown credential ID"
Missing Credentials No stored credentials 404 "No credentials found"
Invalid Origin Unauthorized origin 400 "Invalid origin"

Validation Pipeline

flowchart TD
ReceiveRequest["Receive Request"] --> ValidateJSON{"Valid JSON?"}
ValidateJSON --> |No| JSONError["Return 400 JSON Error"]
ValidateJSON --> |Yes| CheckState{"State Available?"}
CheckState --> |No| StateError["Return 400 State Error"]
CheckState --> |Yes| ValidateChallenge["Validate Challenge"]
ValidateChallenge --> ChallengeValid{"Challenge Valid?"}
ChallengeValid --> |No| ChallengeError["Return 400 Challenge Error"]
ChallengeValid --> |Yes| ValidateOrigin["Validate Origin"]
ValidateOrigin --> OriginValid{"Origin Valid?"}
OriginValid --> |No| OriginError["Return 400 Origin Error"]
OriginValid --> |Yes| ProcessRequest["Process Request"]
ProcessRequest --> Success["Return Success"]
Loading

Diagram sources

  • simple.py
  • simple.py

Section sources

  • simple.py
  • simple.py

Performance Considerations

Stateless Challenge Validation

The system implements efficient stateless challenge validation:

Optimization Technique Implementation Benefit
Constant-Time Comparisons constant_time.bytes_eq() Prevent timing attacks
Lazy Credential Loading Load credentials only when needed Reduce memory usage
Efficient JSON Serialization make_json_safe() function Minimize serialization overhead
Session Cleanup Automatic state clearing Prevent memory leaks

Caching Strategies

While the system is primarily stateless, several caching opportunities exist:

graph TB
subgraph "Caching Opportunities"
PublicKey["Public Key Material<br/>Cached in Memory"]
Metadata["Device Metadata<br/>Cached Locally"]
Certificates["Certificate Chains<br/>Cached Temporarily"]
end
subgraph "Storage Backends"
Memory["In-Memory Cache"]
LocalFS["Local File System"]
Cloud["Cloud Storage"]
end
PublicKey --> Memory
Metadata --> LocalFS
Certificates --> Memory
Memory --> Cloud
Loading

Diagram sources

  • simple.py

Algorithm Selection

The system supports multiple cryptographic algorithms with performance considerations:

Algorithm Family Performance Security Level Use Case
ML-DSA-87 Fast Post-Quantum High-security applications
ML-DSA-65 Medium Post-Quantum Balanced performance/security
ML-DSA-44 Fast Post-Quantum Resource-constrained devices
ES256 Very Fast Classical Legacy compatibility
RS256 Medium Classical Enterprise environments

Section sources

  • simple.py

Security Implementation

Cryptographic Security Features

The simple authentication system implements comprehensive security measures:

graph TB
subgraph "Security Layers"
Crypto["Cryptographic Validation"]
Auth["Authentication"]
Integrity["Data Integrity"]
Replay["Replay Protection"]
end
subgraph "Validation Checks"
SigVerify["Signature Verification"]
CounterCheck["Signature Counter"]
ChallengeVal["Challenge Validation"]
OriginCheck["Origin Validation"]
end
subgraph "Protection Mechanisms"
TimingAttacks["Timing Attack Prevention"]
StateBinding["State Binding"]
SessionIsolation["Session Isolation"]
ErrorHandling["Secure Error Handling"]
end
Crypto --> SigVerify
Crypto --> CounterCheck
Auth --> ChallengeVal
Auth --> OriginCheck
Integrity --> TimingAttacks
Replay --> StateBinding
Replay --> SessionIsolation
Replay --> ErrorHandling
Loading

Diagram sources

  • server.py
  • server.py

Threat Mitigation

Threat Category Mitigation Strategy Implementation
Replay Attacks Signature counters AuthenticatorData counter validation
Timing Attacks Constant-time operations constant_time.bytes_eq() usage
State Tampering Challenge binding Unique challenges per request
Credential Theft Multi-factor support User verification requirements
Man-in-the-Middle Origin validation RP ID hash verification

Section sources

  • server.py
  • server.py

Troubleshooting Guide

Common Issues and Solutions

Registration Failures

Issue: "Registration state not found or has expired"

  • Cause: Session timeout or state corruption
  • Solution: Restart the registration process
  • Prevention: Ensure quick completion of registration flow

Issue: "Invalid signature"

  • Cause: Malformed attestation or corrupted data
  • Solution: Check client-side implementation and retry
  • Debugging: Enable detailed logging for attestation verification

Authentication Failures

Issue: "Unknown credential ID"

  • Cause: Credential not found in storage
  • Solution: Verify credential was properly registered
  • Prevention: Implement credential backup and recovery

Issue: "Wrong challenge in response"

  • Cause: Challenge replay or state mismatch
  • Solution: Clear browser cache and restart authentication
  • Debugging: Check challenge generation and validation logic

Performance Issues

Issue: Slow challenge generation

  • Cause: Insufficient entropy source
  • Solution: Ensure system has adequate entropy
  • Monitoring: Track challenge generation timing

Issue: Memory usage growth

  • Cause: Session state accumulation
  • Solution: Implement session cleanup policies
  • Monitoring: Track session memory usage

Debug Information

The system provides comprehensive debug information:

{
  "debugInfo": {
    "attestationFormat": "packed",
    "algorithmsUsed": [-50],
    "rpIdHashValid": true,
    "rpIdHash": "expected_hash",
    "rpIdHashExpected": "expected_hash",
    "attestationSummary": {
      "signatureValid": true,
      "rootValid": true,
      "rpIdHashValid": true,
      "aaguidMatch": true
    }
  }
}

Section sources

  • simple.py
  • simple.py

Post-Quantum WebAuthn Platform

Getting Started

Architectural Foundations

Cryptography & Security

Authentication Platform

Core Protocol

Flows & Interfaces

Authenticator Capabilities

Server Platform

Frontend Platform

Architecture

Interaction & Utilities

Metadata Service (MDS)

Storage & Data Management

Data Models & Encoding

API Reference

Cross-Platform & HID

Operations & Troubleshooting

Glossary & References

Clone this wiki locally