Authentication Flow Errors - FeitianTech/postquantum-webauthn-platform GitHub Wiki

Authentication Flow Errors

Table of Contents

  1. Introduction
  2. Common Authentication Flow Error Types
  3. Challenge-Response Mismatch Issues
  4. Origin Validation Failures
  5. User Presence Requirement Errors
  6. CBOR Encoding/Decoding Problems
  7. WebAuthn API Error Codes
  8. Credential Creation Options Validation
  9. Browser Developer Tools Integration
  10. User Verification and Resident Key Issues
  11. Attestation Statement Format Validation
  12. Debugging Strategies and Best Practices
  13. Common Client-Side Failure Points
  14. Common Server-Side Failure Points
  15. Troubleshooting Checklist

Introduction

Authentication flow errors in WebAuthn implementations can occur at multiple layers, from client-side JavaScript to server-side validation and CTAP2 command processing. This comprehensive guide covers the most common error scenarios, their root causes, and systematic debugging approaches to resolve them effectively.

The WebAuthn authentication flow involves several critical steps: challenge generation, client-side assertion creation, server-side validation, and attestation verification. Each step can introduce potential failure points that manifest as different types of errors.

Common Authentication Flow Error Types

Registration Flow Errors

Registration errors typically occur during the credential creation ceremony and include:

  • Challenge validation failures: When the client's response doesn't match the expected challenge
  • Origin validation errors: When the origin in the client data doesn't match expectations
  • RP ID hash mismatches: When the relying party ID hash doesn't align with expectations
  • User verification requirement violations: When required user verification isn't satisfied
  • Attestation format validation errors: When attestation statements fail validation

Authentication Flow Errors

Authentication errors occur during the assertion verification process:

  • User presence flag violations: When the user presence flag isn't set appropriately
  • User verification requirement violations: When required user verification isn't performed
  • Signature verification failures: When the cryptographic signature doesn't validate
  • Counter increment issues: When the signature counter doesn't increase as expected

CTAP2 Command Processing Errors

Low-level hardware communication errors:

  • Command parsing failures: When CBOR commands aren't properly formatted
  • Device capability mismatches: When requested operations aren't supported
  • Timeout errors: When operations exceed expected time limits
  • Device state inconsistencies: When device state doesn't match expected conditions

Challenge-Response Mismatch Issues

Root Causes

Challenge-response mismatches are among the most common authentication failures. They occur when the challenge value included in the client data doesn't match the expected challenge stored during the ceremony initiation.

sequenceDiagram
participant Client as "Client Browser"
participant Server as "Authentication Server"
participant Device as "Authenticator Device"
Server->>Client : Send challenge + options
Client->>Device : Request assertion
Device->>Client : Generate response with challenge
Client->>Server : Submit response + challenge
Server->>Server : Validate challenge matches
Note over Server : Challenge mismatch error occurs here
Loading

Diagram sources

  • fido2/server.py
  • server/server/attestation.py

Debugging Challenge Issues

Server-Side Validation Points

The challenge validation occurs in multiple locations:

  1. Basic challenge comparison:

    # From fido2/server.py
    if websafe_decode(state["challenge"]) != client_data.challenge:
        raise ValueError("Wrong challenge in response.")
  2. Advanced challenge validation:

    # From server/attestation.py
    if expected_challenge_bytes and not challenge_matches:
        results["errors"].append("challenge_mismatch")

Common Challenge Mismatch Scenarios

  1. Encoding differences: Base64 vs Base64URL encoding variations
  2. Challenge expiration: Challenges that expire before submission
  3. State corruption: Session state not properly maintained
  4. Cross-origin issues: Challenges generated for different origins

Debugging Steps

  1. Log challenge values:

    console.log('Generated challenge:', generatedChallenge);
    console.log('Submitted challenge:', submittedChallenge);
  2. Compare encoded values:

    function compareChallenges(generated, submitted) {
        const genBytes = websafe_decode(generated);
        const subBytes = websafe_decode(submitted);
        return genBytes.toString() === subBytes.toString();
    }
  3. Validate challenge timing:

    # Check challenge expiration
    challenge_expiration = state.get("challenge_expires")
    if challenge_expiration and challenge_expiration < datetime.utcnow():
        return "Challenge expired"

Section sources

  • fido2/server.py
  • server/server/attestation.py

Origin Validation Failures

Understanding Origin Validation

Origin validation ensures that authentication requests come from legitimate sources and prevents phishing attacks. The origin validation process checks that the client data's origin matches the expected origin for the relying party.

flowchart TD
A["Client Data Received"] --> B["Extract Origin"]
B --> C["Normalize Origin"]
C --> D{"Origin Matches<br/>Expected Value?"}
D --> |No| E["Origin Validation Failed"]
D --> |Yes| F["Origin Validation Passed"]
E --> G["Return Error Response"]
F --> H["Continue Processing"]
Loading

Diagram sources

  • fido2/server.py
  • server/server/attestation.py

Common Origin Validation Issues

Cross-Origin Requests

Cross-origin requests can cause validation failures:

// Example of cross-origin detection
if (clientData.cross_origin) {
    results["errors"].append("cross_origin_not_allowed");
}

Origin Normalization Problems

Different browsers may report origins differently:

  1. Scheme differences: http vs https
  2. Port inclusion: localhost:3000 vs localhost
  3. Trailing slashes: example.com vs example.com/

Debugging Origin Issues

  1. Log origin values:

    console.log('Expected origin:', expectedOrigin);
    console.log('Actual origin:', clientData.origin);
  2. Normalize origins for comparison:

    function normalizeOrigin(origin) {
        try {
            const url = new URL(origin);
            return `${url.protocol}//${url.hostname}${url.port ? ':' + url.port : ''}`;
        } catch (e) {
            return origin.toLowerCase();
        }
    }
  3. Validate origin against allowed list:

    allowed_origins = ["https://example.com", "https://demo.example.com"]
    if client_data.origin not in allowed_origins:
        raise ValueError("Invalid origin")

Section sources

  • fido2/server.py
  • server/server/attestation.py

User Presence Requirement Errors

Understanding User Presence Flags

User presence is a critical security feature that ensures the user is physically interacting with the authenticator. The user presence flag (UP) indicates whether the authenticator detected user presence during the operation.

stateDiagram-v2
[*] --> UserInteraction
UserInteraction --> UserPresenceDetected : User touches device
UserInteraction --> NoUserPresence : No interaction
UserPresenceDetected --> UP_Flag_Set
NoUserPresence --> UP_Flag_NotSet
UP_Flag_Set --> ContinueProcessing
UP_Flag_NotSet --> UserPresenceError
UserPresenceError --> [*]
ContinueProcessing --> [*]
Loading

Diagram sources

  • fido2/webauthn.py

Common User Presence Issues

Required User Verification Not Met

When user verification is required but not performed:

# From fido2/server.py
if (
    state["user_verification"] == UserVerificationRequirement.REQUIRED
    and not auth_data.is_user_verified()
):
    raise ValueError(
        "User verification required, but user verified flag not set."
    )

User Presence Flag Violations

# From fido2/webauthn.py
if not auth_data.is_user_present():
    raise ValueError("User Present flag not set.")

Debugging User Presence Issues

  1. Check authenticator capabilities:

    navigator.credentials.get({
        publicKey: {
            userVerification: 'required'
        }
    }).then(assertion => {
        console.log('User verification enabled:', 
                    assertion.getClientExtensionResults()?.credProps?.uv);
    });
  2. Validate user presence flags:

    flags = auth_data_obj.flags
    user_present = bool(flags & AuthenticatorData.FLAG.UP)
    user_verified = bool(flags & AuthenticatorData.FLAG.UV)
    
    if not user_present:
        results["errors"].append("user_presence_not_set")
  3. Test with different authenticators:

    • Hardware security keys
    • Platform authenticators (Touch ID, Face ID)
    • Biometric authenticators

Section sources

  • fido2/server.py
  • fido2/webauthn.py

CBOR Encoding/Decoding Problems

Understanding CBOR Structure

CBOR (Concise Binary Object Representation) is the primary encoding format used in WebAuthn for transmitting data between clients and servers. CBOR encoding/decoding issues can cause authentication failures at multiple levels.

graph TD
A["Raw Data"] --> B["CBOR Encoder"]
B --> C["Encoded CBOR"]
C --> D["Transmission"]
D --> E["CBOR Decoder"]
E --> F["Decoded Data"]
F --> G["Validation"]
H["Encoding Error"] --> B
I["Decoding Error"] --> E
J["Canonical Validation"] --> E
Loading

Diagram sources

  • fido2/cbor.py

Common CBOR Issues

Non-Canonical CBOR

The server performs strict canonical CBOR validation:

# From fido2/ctap2/base.py
if self._strict_cbor:
    expected = cbor.encode(decoded)
    if expected != enc:
        raise ValueError(
            "Non-canonical CBOR from Authenticator.\n"
            f"Got: {enc.hex()}\nExpected: {expected.hex()}"
        )

Encoding/Decoding Errors

  1. Type mismatches: Incorrect data types in CBOR encoding
  2. Length inconsistencies: Problems with indefinite-length arrays/strings
  3. Tag validation: Invalid CBOR tags or tag values
  4. Float precision: Issues with floating-point encoding

Debugging CBOR Issues

Server-Side CBOR Validation
# From fido2/cbor.py
def decode(data) -> CborType:
    """Decodes data from a CBOR-encoded byte string.
    
    Also validates that no extra data follows the encoded object.
    """
    value, rest = decode_from(data)
    if rest != b"":
        raise ValueError("Extraneous data")
    return value
Client-Side CBOR Inspection
// Inspect CBOR-encoded data in browser
function inspectCborData(encodedData) {
    try {
        const decoder = new CBORDecoder();
        const decoded = decoder.decode(encodedData);
        console.log('Decoded CBOR:', decoded);
        return decoded;
    } catch (error) {
        console.error('CBOR decoding failed:', error);
        return null;
    }
}
CBOR Structure Analysis
# From server/server/decoder/decode.py
def _parse_cbor_item(data: bytes, offset: int) -> Tuple[Dict[str, Any], int]:
    if offset >= len(data):
        raise _CborDecodingError("Unexpected end of CBOR data.", offset)
    
    fb = data[offset]
    major_type = fb >> 5
    info = fb & 0b11111
    
    # Handle different major types
    if major_type == 0:  # Unsigned integer
        value, new_offset = load_int(info, data[offset+1:])
    elif major_type == 1:  # Negative integer
        value, new_offset = load_nint(info, data[offset+1:])
    # ... handle other major types

Section sources

  • fido2/ctap2/base.py
  • fido2/cbor.py
  • server/server/decoder/decode.py

WebAuthn API Error Codes

Standard WebAuthn Error Responses

WebAuthn APIs return standardized error codes that help identify specific failure points in the authentication flow.

Error Code Description Common Causes
INVALID_STATE_ERR Operation not applicable to current state Challenge expired, invalid state transitions
NOT_SUPPORTED_ERR Requested operation not supported Unsupported authenticator, disabled features
SECURITY_ERR Security violation detected Cross-origin requests, invalid signatures
NOT_ALLOWED_ERR Operation not allowed User cancellation, timeout exceeded
UNKNOWN_ERROR Generic error occurred Network issues, device failures

Custom Error Codes in This Implementation

The server implements custom error codes for specific failure scenarios:

// From server/server/static/scripts/advanced/json-editor.js
function validateAuthenticationPublicKey(publicKey) {
    if (publicKey.timeout !== undefined) {
        const timeoutValue = normalizeInteger(publicKey.timeout, 'publicKey.timeout');
        if (timeoutValue !== null && timeoutValue < 0) {
            throw new Error('publicKey.timeout must be zero or greater.');
        }
    }
    
    if (publicKey.rpId !== undefined && 
        (typeof publicKey.rpId !== 'string' || !publicKey.rpId.trim())) {
        throw new Error('publicKey.rpId must be a non-empty string when provided.');
    }
}

Error Response Patterns

Registration Error Responses

// Example error response structure
{
    "error": "Registration state not found or has expired. Please restart the registration process.",
    "errorCode": "STATE_EXPIRED",
    "timestamp": "2024-01-15T10:30:00Z"
}

Authentication Error Responses

// Example authentication error response
{
    "error": "User verification required, but user verified flag not set.",
    "errorCode": "USER_VERIFICATION_REQUIRED",
    "details": {
        "userVerificationRequired": true,
        "userVerified": false,
        "authenticatorFlags": {
            "userPresent": true,
            "userVerified": false
        }
    }
}

Section sources

  • server/server/static/scripts/advanced/json-editor.js

Credential Creation Options Validation

Understanding Credential Options

Credential creation options define the parameters for generating new credentials. Validation failures in these options can prevent successful registration.

flowchart TD
A["Credential Options"] --> B["Algorithm Validation"]
A --> C["Attachment Validation"]
A --> D["User Verification Validation"]
A --> E["Resident Key Validation"]
B --> F["Supported Algorithms"]
C --> G["Platform/Cross-Platform"]
D --> H["Required/Preferred/None"]
E --> I["Required/Preferred/None"]
F --> J{"Validation Passed?"}
G --> J
H --> J
I --> J
J --> |No| K["Return Validation Error"]
J --> |Yes| L["Proceed with Registration"]
Loading

Diagram sources

  • server/server/routes/advanced.py

Common Validation Issues

Algorithm Selection Problems

# From server/server/routes/advanced.py
def _derive_algorithms_from_credentials(credentials: Iterable[Any]) -> List[PublicKeyCredentialParameters]:
    """Produce a list of allowed algorithms based on stored credential data."""
    
    seen: Dict[int, PublicKeyCredentialParameters] = {}
    for credential in credentials:
        alg_value = _extract_credential_algorithm(credential)
        if alg_value is None or alg_value in seen:
            continue
        
        seen[alg_value] = PublicKeyCredentialParameters(
            type=PublicKeyCredentialType.PUBLIC_KEY,
            alg=alg_value,
        )
    
    return list(seen.values())

Attachment Requirement Conflicts

# From server/server/routes/advanced.py
allowed_attachments = request_allowed_attachments
if allowed_attachments:
    response_attachment = normalize_attachment(
        response.get('authenticatorAttachment')
    )
    if response_attachment not in allowed_attachments:
        return jsonify({
            "error": "Authenticator attachment is not permitted by the selected hints."
        }), 400

User Verification Requirement Validation

// From server/server/static/scripts/advanced/json-editor.js
function validateHints(hints, fieldName) {
    if (!Array.isArray(hints)) {
        throw new Error(`${fieldName} must be an array.`);
    }
    
    const validHints = ['platform', 'cross-platform'];
    for (const hint of hints) {
        if (!validHints.includes(hint)) {
            throw new Error(`Invalid hint value: ${hint}`);
        }
    }
}

Debugging Credential Options

Log Validation Results

function logCredentialOptions(options) {
    console.log('Credential Options:', {
        challenge: options.challenge,
        rp: options.rp,
        user: options.user,
        pubKeyCredParams: options.pubKeyCredParams.map(param => ({
            type: param.type,
            alg: param.alg,
            algorithmName: getAlgorithmName(param.alg)
        })),
        authenticatorSelection: options.authenticatorSelection,
        timeout: options.timeout,
        attestation: options.attestation
    });
}

Validate Against Expected Schema

function validateCredentialOptions(options) {
    const errors = [];
    
    // Check required fields
    if (!options.challenge) errors.push('challenge is required');
    if (!options.rp || !options.rp.id) errors.push('rp.id is required');
    if (!options.user || !options.user.name) errors.push('user.name is required');
    
    // Validate algorithm parameters
    if (options.pubKeyCredParams) {
        for (const param of options.pubKeyCredParams) {
            if (!param.type || !param.alg) {
                errors.push('Each pubKeyCredParam must have type and alg');
            }
        }
    }
    
    return errors;
}

Section sources

  • server/server/routes/advanced.py
  • server/server/static/scripts/advanced/json-editor.js

Browser Developer Tools Integration

Using Browser DevTools for Authentication Debugging

Browser developer tools provide powerful capabilities for debugging WebAuthn authentication flows. This section covers systematic approaches to using these tools effectively.

graph LR
A["Browser DevTools"] --> B["Network Tab"]
A --> C["Console Tab"]
A --> D["Application Tab"]
A --> E["Security Tab"]
B --> F["Request/Response Payloads"]
C --> G["JavaScript Error Messages"]
D --> H["Session Storage"]
E --> I["Certificate Information"]
F --> J["Payload Analysis"]
G --> K["Error Tracing"]
H --> L["State Validation"]
I --> M["Security Validation"]
Loading

Network Request Analysis

Capturing Authentication Requests

  1. Enable network monitoring:

    // Enable verbose logging for WebAuthn requests
    console.log('Starting WebAuthn request...');
  2. Inspect request payloads:

    async function debugWebAuthnRequest(endpoint, data) {
        console.log('Request to:', endpoint);
        console.log('Request body:', data);
        
        const response = await fetch(endpoint, {
            method: 'POST',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify(data)
        });
        
        console.log('Response status:', response.status);
        console.log('Response headers:', Object.fromEntries(response.headers.entries()));
        
        const responseBody = await response.json();
        console.log('Response body:', responseBody);
        
        return responseBody;
    }

Analyzing Response Headers

// Extract and log authentication response headers
function logAuthResponseHeaders(response) {
    const headers = {};
    for (const [key, value] of response.headers.entries()) {
        headers[key] = value;
    }
    
    console.log('Response Headers:', {
        'content-type': headers['content-type'],
        'x-frame-options': headers['x-frame-options'],
        'x-content-type-options': headers['x-content-type-options'],
        'permissions-policy': headers['permissions-policy']
    });
}

Console Logging Strategies

Comprehensive Error Logging

// Enhanced error logging for WebAuthn operations
function logWebAuthnError(operation, error) {
    console.group(`WebAuthn ${operation} Error`);
    console.log('Error name:', error.name);
    console.log('Error message:', error.message);
    console.log('Error stack:', error.stack);
    
    if (error.cause) {
        console.log('Error cause:', error.cause);
    }
    
    if (error.webauthnCode) {
        console.log('WebAuthn error code:', error.webauthnCode);
    }
    
    console.groupEnd();
}

State Tracking

// Track authentication state changes
let authenticationState = {
    challenge: null,
    rpId: null,
    userId: null,
    timestamp: Date.now()
};

function updateAuthenticationState(newState) {
    authenticationState = { ...authenticationState, ...newState };
    console.log('Updated authentication state:', authenticationState);
}

Application Storage Inspection

Session Storage Analysis

// Inspect session storage for authentication state
function inspectSessionStorage() {
    const sessionStorageItems = {};
    for (let i = 0; i < sessionStorage.length; i++) {
        const key = sessionStorage.key(i);
        try {
            const value = sessionStorage.getItem(key);
            sessionStorageItems[key] = JSON.parse(value);
        } catch (e) {
            sessionStorageItems[key] = value;
        }
    }
    
    console.log('Session Storage:', sessionStorageItems);
}

Local Storage Validation

// Validate local storage for persistent authentication data
function validateLocalStorage() {
    const localStorageItems = {};
    for (let i = 0; i < localStorage.length; i++) {
        const key = localStorage.key(i);
        if (key.startsWith('webauthn_')) {
            try {
                const value = localStorage.getItem(key);
                localStorageItems[key] = JSON.parse(value);
            } catch (e) {
                localStorageItems[key] = value;
            }
        }
    }
    
    console.log('WebAuthn Local Storage:', localStorageItems);
}

Security Tab Analysis

Certificate Inspection

// Monitor certificate validation in development
function monitorCertificateValidation() {
    if (window.performance && performance.getEntriesByType) {
        const resources = performance.getEntriesByType('resource');
        const certificates = resources.filter(resource => 
            resource.initiatorType === 'script' && 
            resource.name.includes('webauthn')
        );
        
        console.log('Certificate Resources:', certificates);
    }
}

Section sources

  • server/server/static/scripts/shared/auth-debug.js

User Verification and Resident Key Issues

Understanding User Verification Requirements

User verification adds an additional security layer by requiring the user to authenticate through biometrics, PIN, or other verification methods.

flowchart TD
A["User Verification Request"] --> B{"Verification Method Available?"}
B --> |Yes| C["Perform Verification"]
B --> |No| D["Fallback Behavior"]
C --> E{"Verification Successful?"}
E --> |Yes| F["Set UV Flag"]
E --> |No| G["Return Verification Error"]
F --> H["Allow Authentication"]
G --> I["Deny Authentication"]
D --> J{"Required?"}
J --> |Yes| G
J --> |No| H
Loading

Diagram sources

  • fido2/webauthn.py

Common User Verification Issues

Verification Method Unavailability

# From fido2/webauthn.py
@unique
class UserVerificationRequirement(_StringEnum):
    REQUIRED = "required"
    PREFERRED = "preferred"
    DISCOURAGED = "discouraged"

Resident Key Configuration Problems

Resident keys (discoverable credentials) allow storing credentials on the authenticator itself:

# From fido2/webauthn.py
@unique
class ResidentKeyRequirement(_StringEnum):
    REQUIRED = "required"
    PREFERRED = "preferred"
    DISCOURAGED = "discouraged"

Debugging User Verification Issues

Check Authenticator Capabilities

// Determine authenticator capabilities
async function checkAuthenticatorCapabilities() {
    const info = await navigator.credentials.get({
        publicKey: {
            challenge: new Uint8Array(32),
            allowCredentials: [],
            userVerification: 'required'
        }
    });
    
    console.log('Authenticator capabilities:', {
        residentKeys: info.getResidentKeys?.(),
        userVerification: info.getUserVerification?.(),
        extensions: info.getExtensions?.()
    });
}

Validate Verification Requirements

// Validate user verification requirements
function validateUserVerificationRequirements(options) {
    const requirements = {
        required: false,
        preferred: false,
        discouraged: false
    };
    
    if (options.authenticatorSelection) {
        const selection = options.authenticatorSelection;
        if (selection.userVerification === 'required') {
            requirements.required = true;
        } else if (selection.userVerification === 'preferred') {
            requirements.preferred = true;
        } else if (selection.userVerification === 'discouraged') {
            requirements.discouraged = true;
        }
    }
    
    return requirements;
}

Monitor Verification Status

// Monitor verification status during authentication
async function monitorVerificationStatus(assertion) {
    const clientExtensions = assertion.getClientExtensionResults();
    const credProps = clientExtensions?.credProps;
    
    console.log('Verification status:', {
        userVerified: credProps?.uv,
        residentKey: credProps?.rk,
        verificationMethod: credProps?.verificationMethod
    });
}

Section sources

  • fido2/webauthn.py
  • fido2/webauthn.py

Attestation Statement Format Validation

Understanding Attestation Formats

Attestation statements provide evidence about the authenticator's characteristics and security properties. Different attestation formats require specific validation procedures.

graph TD
A["Attestation Object"] --> B["Format Detection"]
B --> C{"Format Type"}
C --> |packed| D["Packed Attestation"]
C --> |fido-u2f| E["U2F Attestation"]
C --> |android-key| F["Android Key Attestation"]
C --> |android-safetynet| G["Android SafetyNet Attestation"]
C --> |apple| H["Apple Attestation"]
C --> |tpm| I["TPM Attestation"]
C --> |none| J["Self Attestation"]
D --> K["Format-Specific Validation"]
E --> K
F --> K
G --> K
H --> K
I --> K
J --> K
K --> L["Root Certificate Validation"]
L --> M["Signature Verification"]
M --> N["Attestation Trust Evaluation"]
Loading

Diagram sources

  • server/server/attestation.py

Common Attestation Validation Issues

Root Certificate Chain Problems

# From server/server/attestation.py
def _evaluate_classical_attestation_root(
    attestation_object: AttestationObject,
    attestation_result: Any,
    client_data_hash: bytes,
    verifier: Optional[Any],
    now: datetime,
) -> Dict[str, Any]:
    """Evaluate attestation trust using classical x509 verification."""
    
    trust_path = list(getattr(attestation_result, "trust_path", []) or [])
    
    # Verify certificate chain
    try:
        verify_x509_chain(list(trust_path))
    except InvalidSignature:
        manual_chain_valid = False
    except Exception as exc:
        errors.append(f"certificate_chain_error: {exc}")
        manual_chain_valid = False

Algorithm Compatibility Issues

# From server/server/attestation.py
def _normalise_pqc_algorithm_identifier(value: Any) -> Optional[int]:
    """Return the COSE identifier for a PQC algorithm when discernible."""
    
    if isinstance(value, int) and is_pqc_algorithm(value):
        return value
    
    if isinstance(value, str):
        # Try to parse algorithm name or ID
        try:
            parsed = int(value, 10)
        except ValueError:
            parsed = None
        
        if parsed is not None and is_pqc_algorithm(parsed):
            return parsed
        
        # Try to match algorithm name
        lowered = value.strip().lower()
        mapped = _PQC_ALGORITHM_NAME_TO_ID.get(lowered)
        if mapped is not None:
            return mapped

Debugging Attestation Issues

Log Attestation Details

// Log attestation details for debugging
function logAttestationDetails(attestationObject) {
    console.log('Attestation Object:', {
        format: attestationObject.format,
        authData: attestationObject.authData,
        attStmt: attestationObject.attStmt,
        raw: Array.from(new Uint8Array(attestationObject.raw))
    });
}

Validate Attestation Chain

// Validate attestation chain structure
function validateAttestationChain(attestationObject) {
    const attStmt = attestationObject.attStmt;
    const x5c = attStmt.x5c;
    
    if (!x5c || !Array.isArray(x5c)) {
        throw new Error('Attestation chain missing or invalid');
    }
    
    console.log('Attestation chain length:', x5c.length);
    
    // Validate each certificate in the chain
    x5c.forEach((cert, index) => {
        try {
            const decodedCert = decodeCertificate(cert);
            console.log(`Certificate ${index}:`, {
                subject: decodedCert.subject,
                issuer: decodedCert.issuer,
                validFrom: decodedCert.validFrom,
                validTo: decodedCert.validTo
            });
        } catch (error) {
            console.error(`Certificate ${index} validation failed:`, error);
        }
    });
}

Check Algorithm Support

// Check if algorithm is supported
function isAlgorithmSupported(algorithmId) {
    const supportedAlgorithms = [
        -7, // ES256
        -257, // RS256
        -8, // EDDSA
        // ... other supported algorithms
    ];
    
    return supportedAlgorithms.includes(algorithmId);
}

Section sources

  • server/server/attestation.py
  • server/server/attestation.py

Debugging Strategies and Best Practices

Systematic Debugging Approach

Effective debugging of WebAuthn authentication flows requires a systematic approach that examines each layer of the authentication process.

flowchart TD
A["Authentication Failure"] --> B["Collect Error Information"]
B --> C["Analyze Client-Side Logs"]
C --> D["Examine Server Logs"]
D --> E["Validate Network Traffic"]
E --> F["Check Authenticator State"]
F --> G["Review Configuration"]
G --> H["Identify Root Cause"]
H --> I["Apply Fix"]
I --> J["Verify Resolution"]
Loading

Logging Best Practices

Comprehensive Server Logging

# Enhanced logging for authentication flows
import logging
from datetime import datetime

def setup_authentication_logging():
    logging.basicConfig(level=logging.DEBUG)
    logger = logging.getLogger('authentication')
    
    # Add correlation ID for request tracing
    def log_authentication_event(event_type, request, response=None, error=None):
        correlation_id = request.headers.get('X-Correlation-ID', 'unknown')
        timestamp = datetime.utcnow().isoformat()
        
        log_entry = {
            'timestamp': timestamp,
            'correlation_id': correlation_id,
            'event_type': event_type,
            'request_method': request.method,
            'request_path': request.path,
            'user_agent': request.headers.get('User-Agent'),
            'remote_addr': request.remote_addr
        }
        
        if response:
            log_entry['response_status'] = response.status_code
            log_entry['response_time'] = response.elapsed.total_seconds()
        
        if error:
            log_entry['error'] = str(error)
            log_entry['error_type'] = type(error).__name__
        
        logger.debug(log_entry)

Client-Side Debugging Utilities

// Comprehensive debugging utilities
class WebAuthnDebugger {
    constructor() {
        this.logs = [];
        this.enabled = true;
    }
    
    enable() {
        this.enabled = true;
        console.log('WebAuthn debugging enabled');
    }
    
    disable() {
        this.enabled = false;
        console.log('WebAuthn debugging disabled');
    }
    
    log(level, message, data = null) {
        if (!this.enabled) return;
        
        const timestamp = new Date().toISOString();
        const logEntry = {
            timestamp,
            level,
            message,
            data: data ? this.sanitizeData(data) : null
        };
        
        this.logs.push(logEntry);
        console[level.toLowerCase()](message, data);
    }
    
    sanitizeData(data) {
        // Remove sensitive information
        const sanitized = {...data};
        delete sanitized.privateKey;
        delete sanitized.secretKey;
        delete sanitized.password;
        return sanitized;
    }
    
    exportLogs() {
        return JSON.stringify(this.logs, null, 2);
    }
}

const debugger = new WebAuthnDebugger();

Error Recovery Strategies

Graceful Degradation

// Implement graceful degradation for authentication failures
async function safeWebAuthnOperation(operation, fallback) {
    try {
        return await operation();
    } catch (error) {
        debugger.log('error', 'WebAuthn operation failed', error);
        
        // Attempt fallback authentication
        if (fallback) {
            debugger.log('warn', 'Attempting fallback authentication');
            return fallback();
        }
        
        throw error;
    }
}

Retry Mechanisms

// Implement retry logic for transient failures
async function retryWithBackoff(operation, maxRetries = 3, baseDelay = 1000) {
    let lastError;
    
    for (let attempt = 1; attempt <= maxRetries; attempt++) {
        try {
            return await operation();
        } catch (error) {
            lastError = error;
            
            if (attempt < maxRetries) {
                const delay = baseDelay * Math.pow(2, attempt - 1);
                debugger.log('warn', `Attempt ${attempt} failed, retrying in ${delay}ms`);
                await new Promise(resolve => setTimeout(resolve, delay));
            }
        }
    }
    
    throw lastError;
}

Section sources

  • server/server/static/scripts/shared/auth-debug.js

Common Client-Side Failure Points

JavaScript Runtime Issues

Client-side failures often stem from JavaScript runtime problems, browser compatibility issues, or DOM manipulation errors.

Promise Rejection Handling

// Comprehensive promise rejection handling
function handlePromiseRejection(promise, context) {
    promise.catch(error => {
        debugger.log('error', `Promise rejection in ${context}`, {
            error: error.message,
            stack: error.stack,
            name: error.name
        });
        
        // Provide user-friendly error message
        showErrorMessage(`Authentication failed: ${error.message}`);
    });
}

// Example usage
handlePromiseRejection(
    navigator.credentials.get(credentialRequestOptions),
    'navigator.credentials.get'
);

Browser Compatibility Issues

// Check for WebAuthn API availability
function checkWebAuthnSupport() {
    const features = {
        webauthn: typeof navigator?.credentials?.get === 'function',
        subtleCrypto: typeof crypto?.subtle === 'object',
        bufferSource: typeof ArrayBuffer !== 'undefined',
        base64: typeof btoa === 'function'
    };
    
    if (!features.webauthn) {
        debugger.log('error', 'WebAuthn API not supported');
        return false;
    }
    
    if (!features.subtleCrypto) {
        debugger.log('error', 'Subtle Crypto API not supported');
        return false;
    }
    
    return true;
}

DOM and Event Handling Issues

Event Listener Problems

// Robust event listener implementation
class WebAuthnEventHandler {
    constructor(element) {
        this.element = element;
        this.listeners = new Map();
    }
    
    addEventListener(eventName, handler, options = {}) {
        const wrappedHandler = (...args) => {
            try {
                return handler(...args);
            } catch (error) {
                debugger.log('error', `Event handler error (${eventName}):`, error);
                // Prevent error propagation
                if (options.preventDefault !== false) {
                    args[0]?.preventDefault();
                }
            }
        };
        
        this.element.addEventListener(eventName, wrappedHandler, options);
        this.listeners.set(eventName, wrappedHandler);
    }
    
    removeEventListeners() {
        for (const [eventName, handler] of this.listeners) {
            this.element.removeEventListener(eventName, handler);
        }
        this.listeners.clear();
    }
}

Form Validation Issues

// Enhanced form validation
function validateWebAuthnForm(form) {
    const errors = [];
    
    // Check required fields
    const requiredFields = ['username', 'challenge'];
    requiredFields.forEach(field => {
        const input = form.querySelector(`[name="${field}"]`);
        if (!input || !input.value.trim()) {
            errors.push(`${field} is required`);
        }
    });
    
    // Validate challenge format
    const challengeInput = form.querySelector('[name="challenge"]');
    if (challengeInput && challengeInput.value) {
        try {
            // Attempt to decode challenge
            websafe_decode(challengeInput.value);
        } catch (error) {
            errors.push('Invalid challenge format');
        }
    }
    
    return errors;
}

Section sources

  • server/server/static/scripts/advanced/json-editor.js

Common Server-Side Failure Points

Route Handler Issues

Server-side route handlers can fail due to various reasons including malformed requests, missing dependencies, or configuration errors.

Request Validation Failures

# Comprehensive request validation
def validate_registration_request(request):
    """Validate incoming registration request."""
    errors = []
    
    # Check content type
    if request.content_type != 'application/json':
        errors.append('Content-Type must be application/json')
    
    # Parse JSON
    try:
        data = request.get_json(silent=True)
        if data is None:
            errors.append('Invalid JSON in request body')
    except Exception as e:
        errors.append(f'Failed to parse JSON: {str(e)}')
        data = {}
    
    # Validate required fields
    required_fields = ['challenge', 'rp', 'user']
    for field in required_fields:
        if field not in data:
            errors.append(f'Missing required field: {field}')
    
    return errors, data

State Management Issues

# Robust session state management
def manage_authentication_state(session, state_data):
    """Manage authentication state with proper validation."""
    
    # Validate state structure
    required_state_fields = ['challenge', 'challenge_expires', 'user_verification']
    for field in required_state_fields:
        if field not in state_data:
            raise ValueError(f'Missing required state field: {field}')
    
    # Check challenge expiration
    challenge_expires = state_data.get('challenge_expires')
    if challenge_expires and challenge_expires < datetime.utcnow():
        session.pop('authentication_state', None)
        raise ValueError('Challenge expired')
    
    # Store validated state
    session['authentication_state'] = state_data
    return True

Dependency and Configuration Issues

Cryptographic Library Problems

# Secure cryptographic operations
def secure_cryptographic_operation(data, algorithm='sha256'):
    """Perform cryptographic operations with proper error handling."""
    
    try:
        # Validate input data
        if not isinstance(data, (bytes, bytearray, memoryview)):
            data = str(data).encode('utf-8')
        
        # Perform hashing
        hash_func = getattr(hashlib, algorithm, None)
        if not hash_func:
            raise ValueError(f'Unsupported hash algorithm: {algorithm}')
        
        return hash_func(data).digest()
    
    except Exception as e:
        debugger.log('error', 'Cryptographic operation failed:', {
            'error': str(e),
            'algorithm': algorithm,
            'data_type': type(data).__name__
        })
        raise

Database Connection Issues

# Reliable database operations
class DatabaseManager:
    def __init__(self):
        self.connection_pool = None
        self.max_retries = 3
    
    async def execute_query(self, query, params=None):
        """Execute database query with retry logic."""
        
        for attempt in range(self.max_retries):
            try:
                if not self.connection_pool:
                    await self.initialize_connection_pool()
                
                async with self.connection_pool.acquire() as connection:
                    result = await connection.fetch(query, *(params or []))
                    return result
                
            except psycopg2.OperationalError as e:
                if attempt < self.max_retries - 1:
                    wait_time = 2 ** attempt
                    await asyncio.sleep(wait_time)
                    continue
                raise DatabaseConnectionError(f'Failed after {self.max_retries} attempts: {e}')
            
            except Exception as e:
                debugger.log('error', 'Database operation failed:', {
                    'attempt': attempt + 1,
                    'error': str(e),
                    'query': query[:100]  # Log truncated query
                })
                raise

Section sources

  • server/server/routes/simple.py
  • server/server/routes/advanced.py

Troubleshooting Checklist

Pre-Authentication Checklist

Environment Setup

  • Browser Support: Verify WebAuthn API availability
  • HTTPS Requirement: Confirm secure context (HTTPS)
  • Feature Flags: Check browser feature support
  • Polyfills: Ensure appropriate polyfills are loaded

Configuration Validation

  • RP ID Configuration: Verify relying party ID settings
  • Origin Whitelist: Confirm allowed origins
  • Challenge Generation: Test challenge creation
  • Session Management: Validate session handling

Client-Side Preparation

  • JavaScript Loading: Confirm script loading
  • DOM Ready: Verify DOM readiness
  • Event Handlers: Check event listener setup
  • Form Validation: Test form validation

During Authentication Flow

Registration Phase

  • Challenge Validation: Verify challenge matches
  • Origin Verification: Confirm origin correctness
  • User Presence: Check user interaction
  • Attestation Format: Validate attestation type

Authentication Phase

  • Assertion Creation: Verify assertion generation
  • Signature Validation: Check signature verification
  • Counter Validation: Confirm counter updates
  • User Verification: Validate user verification

Post-Authentication Review

Error Analysis

  • Error Messages: Capture detailed error information
  • Stack Traces: Collect complete stack traces
  • Request/Response: Log complete request/response pairs
  • Timing Information: Record operation timings

State Validation

  • Session State: Verify session integrity
  • Database Records: Check database consistency
  • Cache Entries: Validate cache state
  • Log Entries: Review log completeness

Advanced Debugging Techniques

Network Analysis

  • Packet Capture: Use Wireshark for network analysis
  • Certificate Inspection: Verify certificate chains
  • Timing Analysis: Measure operation latencies
  • Rate Limiting: Check rate limiting effects

Authenticator Testing

  • Multiple Devices: Test with different authenticators
  • Firmware Versions: Verify firmware compatibility
  • Security Policies: Check security policy enforcement
  • Error Conditions: Test error scenarios

Performance Monitoring

  • Resource Usage: Monitor CPU and memory usage
  • Network Latency: Measure network delays
  • Database Performance: Check database query times
  • Cache Efficiency: Monitor cache hit rates

This comprehensive troubleshooting checklist provides a systematic approach to identifying and resolving authentication flow errors in WebAuthn implementations. Regular review and testing of these areas can significantly improve system reliability and user experience.

⚠️ **GitHub.com Fallback** ⚠️