-
Notifications
You must be signed in to change notification settings - Fork 0
Simple Authentication Flow Endpoints
- Introduction
- Architecture Overview
- Registration Endpoints
- Authentication Endpoints
- Session Management
- Credential Storage
- Frontend Integration
- Security Considerations
- Error Handling
- Examples
The Post-Quantum WebAuthn Platform provides a simplified authentication flow through four core endpoints that enable secure passkey registration and authentication. This simple flow uses default configurations optimized for post-quantum cryptographic algorithms while maintaining compatibility with standard WebAuthn protocols.
The authentication system supports both classical and post-quantum cryptographic algorithms, automatically selecting appropriate COSE algorithm parameters and handling attestation verification for enhanced security. The platform integrates seamlessly with modern browsers' WebAuthn APIs while providing robust session management and credential persistence.
The simple authentication flow consists of two main phases: registration and authentication. Each phase involves coordinated interactions between frontend JavaScript, backend API endpoints, and underlying storage systems.
sequenceDiagram
participant Client as "Browser Client"
participant Frontend as "Frontend JS"
participant Backend as "API Server"
participant Storage as "Credential Storage"
participant Authenticator as "Authenticator Device"
Note over Client,Authenticator : Registration Flow
Client->>Frontend : User clicks Register
Frontend->>Backend : POST /api/register/begin
Backend-->>Frontend : Registration Options
Frontend->>Authenticator : WebAuthn Create Request
Authenticator-->>Frontend : Generated Credential
Frontend->>Backend : POST /api/register/complete
Backend->>Storage : Store Credential Data
Storage-->>Backend : Confirmation
Backend-->>Frontend : Registration Success
Note over Client,Authenticator : Authentication Flow
Client->>Frontend : User clicks Authenticate
Frontend->>Backend : POST /api/authenticate/begin
Backend-->>Frontend : Authentication Options
Frontend->>Authenticator : WebAuthn Get Request
Authenticator-->>Frontend : Assertion Response
Frontend->>Backend : POST /api/authenticate/complete
Backend-->>Frontend : Authentication Success
Diagram sources
- server/server/routes/simple.py
- server/server/routes/simple.py
- server/server/static/scripts/simple/auth-simple.js
- server/server/static/scripts/simple/auth-simple.js
HTTP Method: POST
URL Pattern: /api/register/begin?email={email}
This endpoint initiates the registration process by generating registration options with appropriate COSE algorithm parameters and attestation configurations.
| Parameter | Type | Location | Description |
|---|---|---|---|
email |
string | Query | User email address for credential association |
credentials |
array | Body | Existing credentials to exclude from registration |
existingCredentials |
array | Body | Alternative parameter name for existing credentials |
{
"credentials": [
{
"credentialId": "base64url_encoded_id",
"aaguid": "base64url_encoded_aaguid",
"publicKey": "base64url_encoded_public_key",
"algorithm": -49,
"signCount": 0
}
]
}{
"status": "OK",
"publicKey": {
"challenge": "base64url_encoded_challenge",
"rp": {
"id": "example.com",
"name": "Example RP"
},
"user": {
"id": "base64url_encoded_user_id",
"name": "a_user",
"displayName": "A. User"
},
"pubKeyCredParams": [
{
"type": "public-key",
"alg": -49
},
{
"type": "public-key",
"alg": -50
}
],
"timeout": 90000,
"attestation": "none",
"authenticatorSelection": {
"authenticatorAttachment": "cross-platform",
"requireResidentKey": false,
"userVerification": "discouraged"
}
},
"__session_state": "session_state_data"
}The registration begin endpoint performs several critical operations:
- Session Management: Stores registration state and public key options in the Flask session
- Algorithm Selection: Filters available COSE algorithms to include only supported post-quantum and classical algorithms
- Existing Credentials: Processes existing credentials to exclude them from the new registration
- RP Configuration: Determines relying party ID and creates appropriate registration options
Section sources
- server/server/routes/simple.py
HTTP Method: POST
URL Pattern: /api/register/complete?email={email}
This endpoint completes the registration process by validating the attestation response, performing security checks, and storing the credential data.
| Parameter | Type | Location | Description |
|---|---|---|---|
email |
string | Query | User email address associated with registration |
response |
object | Body | WebAuthn registration response from authenticator |
__session_state |
object | Body | Session state for validation (optional) |
{
"id": "base64url_encoded_credential_id",
"rawId": "base64url_encoded_credential_id",
"response": {
"attestationObject": "base64url_encoded_attestation_object",
"clientDataJSON": "base64url_encoded_client_data"
},
"type": "public-key",
"clientExtensionResults": {},
"__session_state": {
"challenge": "base64url_encoded_challenge",
"timeout": 90000,
"rpId": "example.com"
}
}{
"status": "OK",
"algo": "ML-DSA-65 (PQC)",
"attestationFormat": "packed",
"storedCredential": {
"type": "simple",
"email": "user@example.com",
"userName": "user@example.com",
"displayName": "user@example.com",
"credentialId": "base64_encoded_credential_id",
"credentialIdBase64Url": "base64url_encoded_credential_id",
"aaguid": "base64url_encoded_aaguid",
"publicKey": "base64_encoded_public_key",
"publicKeyAlgorithm": -49,
"signCount": 0,
"createdAt": 1640995200.0,
"attestationFormat": "packed",
"properties": {
"attestationSignatureValid": true,
"attestationRootValid": true,
"attestationRpIdHashValid": true,
"attestationAaguidMatch": true
}
},
"relyingParty": {
"attestationFmt": "packed",
"credentialId": "hex_encoded_credential_id",
"publicKeyAlgorithm": -49,
"registrationData": {
"flags": {
"UP": true,
"UV": false,
"AT": true,
"ED": false
},
"signatureCounter": 0
}
}
}The registration completion endpoint implements a comprehensive validation pipeline:
- State Validation: Verifies session state and challenge integrity
- Attestation Processing: Extracts and validates attestation statements
- Security Checks: Performs signature validation, root certificate verification, and RP ID hash validation
- Credential Storage: Persists credential data with metadata and properties
- Session Cleanup: Removes temporary session data
Section sources
- server/server/routes/simple.py
HTTP Method: POST
URL Pattern: /api/authenticate/begin?email={email}
This endpoint initiates the authentication process by retrieving stored credentials and generating authentication options.
| Parameter | Type | Location | Description |
|---|---|---|---|
email |
string | Query | User email address for credential lookup |
credentials |
array | Body | Stored credentials for authentication |
storedCredentials |
array | Body | Alternative parameter name for stored credentials |
{
"credentials": [
{
"credentialId": "base64url_encoded_id",
"aaguid": "base64url_encoded_aaguid",
"publicKey": "base64url_encoded_public_key",
"algorithm": -49,
"signCount": 0
}
]
}{
"publicKey": {
"challenge": "base64url_encoded_challenge",
"rpId": "example.com",
"allowCredentials": [
{
"type": "public-key",
"id": "base64url_encoded_credential_id"
}
],
"timeout": 90000,
"userVerification": "discouraged"
},
"__session_state": "session_state_data"
}The authentication begin endpoint:
- Credential Retrieval: Fetches stored credentials from session or storage
- Option Generation: Creates authentication options with appropriate challenges
- State Management: Stores authentication state for session validation
- Error Handling: Returns 404 if no credentials are found for the user
Section sources
- server/server/routes/simple.py
HTTP Method: POST
URL Pattern: /api/authenticate/complete?email={email}
This endpoint completes the authentication process by validating the assertion response and updating credential counters.
| Parameter | Type | Location | Description |
|---|---|---|---|
email |
string | Query | User email address for authentication |
response |
object | Body | WebAuthn assertion response from authenticator |
__session_state |
object | Body | Session state for validation (optional) |
{
"id": "base64url_encoded_credential_id",
"rawId": "base64url_encoded_credential_id",
"response": {
"authenticatorData": "base64url_encoded_authenticator_data",
"clientDataJSON": "base64url_encoded_client_data",
"signature": "base64url_encoded_signature",
"userHandle": "base64url_encoded_user_handle"
},
"type": "public-key",
"clientExtensionResults": {},
"__session_state": {
"challenge": "base64url_encoded_challenge",
"timeout": 90000,
"rpId": "example.com"
}
}{
"status": "OK",
"authenticatedCredentialId": "base64url_encoded_credential_id",
"signCount": 123
}The authentication completion endpoint:
- State Validation: Verifies session state and challenge integrity
- Assertion Verification: Validates the authenticator's signature and data
- Counter Update: Updates the credential's signature counter
- Session Cleanup: Removes authentication state from session
- Success Response: Returns authentication confirmation with updated counter
Section sources
- server/server/routes/simple.py
The simple authentication flow uses Flask session management for temporary state storage during registration and authentication processes.
graph TD
A[Flask Session] --> B[state]
A --> C[simple_credentials]
A --> D[simple_credentials_email]
A --> E[simple_register_public_key]
A --> F[register_rp_id]
A --> G[authenticate_rp_id]
B --> B1[Registration/Authentication State]
C --> C1[Stored Credentials List]
D --> D1[Associated Email]
E --> E1[Registration Public Key Options]
F --> F1[Registration Relying Party ID]
G --> G1[Authentication Relying Party ID]
Diagram sources
- server/server/routes/simple.py
- server/server/routes/simple.py
The session management follows a strict lifecycle pattern:
-
Registration Phase:
-
state: Stores registration challenge and options -
simple_register_public_key: Contains public key parameters -
register_rp_id: Relying party identifier
-
-
Authentication Phase:
-
state: Stores authentication challenge and options -
authenticate_rp_id: Relying party identifier -
simple_credentials: List of stored credentials
-
-
Cleanup:
- Sessions are automatically cleared after successful completion
- Temporary data is removed to prevent replay attacks
Section sources
- server/server/routes/simple.py
- server/server/routes/simple.py
The platform implements a dual-storage system supporting both local filesystem storage and Google Cloud Storage for credential persistence.
graph TB
subgraph "Storage Backends"
A[Local Filesystem]
B[Google Cloud Storage]
end
subgraph "Storage Components"
C[Credential Data]
D[Metadata]
E[Session Data]
end
subgraph "Storage Operations"
F[savekey]
G[readkey]
H[delkey]
I[iter_credentials]
end
A --> C
B --> C
A --> D
B --> D
A --> E
B --> E
F --> A
F --> B
G --> A
G --> B
H --> A
H --> B
I --> A
I --> B
Diagram sources
- server/server/storage.py
- server/server/storage.py
Each stored credential contains comprehensive metadata and cryptographic material:
| Field | Type | Description |
|---|---|---|
credential_data |
object | Attested credential data from authenticator |
auth_data |
object | Authenticator data and flags |
user_info |
object | User identity information |
registration_time |
number | Unix timestamp of registration |
client_data_json |
string | Base64-encoded client data |
attestation_object |
string | Base64-encoded attestation object |
attestation_format |
string | Attestation format type |
attestation_statement |
object | Attestation statement data |
client_extension_outputs |
object | Client extension results |
properties |
object | Additional credential properties |
The storage system provides atomic operations for credential management:
- Save Operation: Serializes and persists credential data using pickle
- Read Operation: Deserializes stored credential data
- Delete Operation: Removes credential data and associated metadata
- Iterate Operation: Enumerates all stored credentials
Section sources
- server/server/storage.py
- server/server/storage.py
The frontend integration provides seamless WebAuthn API interaction through JavaScript modules that handle the complete authentication flow.
sequenceDiagram
participant UI as "User Interface"
participant JS as "auth-simple.js"
participant WebAuthn as "WebAuthn API"
participant Server as "API Server"
Note over UI,Server : Registration Flow
UI->>JS : simpleRegister()
JS->>Server : POST /api/register/begin
Server-->>JS : Registration Options
JS->>WebAuthn : create(options)
WebAuthn-->>JS : Generated Credential
JS->>Server : POST /api/register/complete
Server-->>JS : Registration Result
JS->>UI : Display Success Message
Note over UI,Server : Authentication Flow
UI->>JS : simpleAuthenticate()
JS->>Server : POST /api/authenticate/begin
Server-->>JS : Authentication Options
JS->>WebAuthn : get(options)
WebAuthn-->>JS : Assertion Response
JS->>Server : POST /api/authenticate/complete
Server-->>JS : Authentication Result
JS->>UI : Display Success Message
Diagram sources
- server/server/static/scripts/simple/auth-simple.js
- server/server/static/scripts/simple/auth-simple.js
The frontend implements comprehensive error handling for various WebAuthn scenarios:
| Error Type | Browser Error | User-Friendly Message |
|---|---|---|
| Cancelled | NotAllowedError |
"User cancelled or authenticator not available" |
| Already Registered | InvalidStateError |
"Authenticator is already registered for this account" |
| Security Issue | SecurityError |
"Security error - check your connection and try again" |
| Not Supported | NotSupportedError |
"WebAuthn is not supported in this browser" |
The frontend maintains a local credential cache using browser localStorage for offline access and improved performance:
- Credential Persistence: Stores generated credentials locally
- Automatic Loading: Loads stored credentials for authentication
- Counter Updates: Updates signature counts after successful authentication
- Cleanup: Provides mechanisms to clear stored credentials
Section sources
- server/server/static/scripts/simple/auth-simple.js
- server/server/static/scripts/simple/auth-simple.js
- server/server/static/scripts/shared/local-storage.js
The simple authentication flow implements multiple layers of security to protect against common attack vectors and ensure cryptographic integrity.
The backend implements comprehensive input validation:
- Challenge Validation: Ensures challenges are properly formatted and not expired
- Credential ID Validation: Validates credential identifiers and prevents tampering
- Signature Verification: Cryptographically verifies all signatures and attestations
- RP ID Verification: Validates relying party identifiers and hashes
Session state management incorporates several security measures:
- Challenge Binding: Associates challenges with specific sessions
- Timeout Protection: Implements reasonable timeouts for authentication flows
- State Isolation: Prevents cross-session state leakage
- Cleanup Mechanisms: Automatically clears sensitive data after completion
The platform implements robust attestation verification:
- Certificate Chain Validation: Verifies complete certificate chains
- Root Certificate Trust: Validates against trusted root certificates
- Algorithm Integrity: Ensures cryptographic algorithm consistency
- Metadata Verification: Cross-references with FIDO Metadata Service
Multiple mechanisms prevent replay attacks:
- Challenge Uniqueness: Each challenge is unique and single-use
- Timestamp Validation: Validates timestamps and expiration
- Counter Monitoring: Tracks and validates signature counters
- Session Isolation: Maintains separate sessions for different operations
Section sources
- server/server/routes/simple.py
- server/server/attestation.py
The authentication endpoints implement structured error handling with meaningful error messages and appropriate HTTP status codes.
| Endpoint | Error Conditions | HTTP Status | Response Format |
|---|---|---|---|
/api/register/begin |
Invalid email format, malformed credentials | 400 | { "error": "message" } |
/api/register/complete |
Missing session state, invalid attestation | 400 | { "error": "message" } |
/api/authenticate/begin |
No credentials found, invalid email | 404 | { "error": "message" } |
/api/authenticate/complete |
Authentication state expired, invalid signature | 400 | { "error": "message" } |
- State Expiration: Clear expired session state automatically
- Retry Mechanisms: Allow retry with fresh challenges
- Graceful Degradation: Provide fallback options for unsupported features
- User Guidance: Offer clear instructions for resolving common errors
Section sources
- server/server/routes/simple.py
- server/server/routes/simple.py
curl -X POST "https://example.com/api/register/begin?email=user@example.com" \
-H "Content-Type: application/json" \
-d '{}'Response:
{
"publicKey": {
"challenge": "dGVzdF9jaGFsbGVuZ2U=",
"rp": {
"id": "example.com",
"name": "Example RP"
},
"user": {
"id": "dXNlcg==",
"name": "a_user",
"displayName": "A. User"
},
"pubKeyCredParams": [
{
"type": "public-key",
"alg": -49
}
],
"timeout": 90000,
"attestation": "none",
"authenticatorSelection": {
"authenticatorAttachment": "cross-platform",
"requireResidentKey": false,
"userVerification": "discouraged"
}
},
"__session_state": "eyJjaGFsbGVuZ2UiOiAi...",
"status": "OK"
}curl -X POST "https://example.com/api/register/complete?email=user@example.com" \
-H "Content-Type: application/json" \
-d '{
"id": "credential_id",
"rawId": "credential_id",
"response": {
"attestationObject": "base64_encoded_attestation",
"clientDataJSON": "base64_encoded_client_data"
},
"type": "public-key",
"__session_state": {
"challenge": "dGVzdF9jaGFsbGVuZ2U="
}
}'Response:
{
"status": "OK",
"algo": "ML-DSA-65 (PQC)",
"storedCredential": {
"type": "simple",
"email": "user@example.com",
"credentialId": "base64_encoded_id",
"publicKeyAlgorithm": -49,
"signCount": 0,
"createdAt": 1640995200.0
},
"relyingParty": {
"attestationFmt": "packed",
"credentialId": "hex_encoded_id",
"publicKeyAlgorithm": -49
}
}curl -X POST "https://example.com/api/authenticate/begin?email=user@example.com" \
-H "Content-Type: application/json" \
-d '{
"credentials": [
{
"credentialId": "base64url_encoded_id",
"aaguid": "base64url_encoded_aaguid",
"publicKey": "base64url_encoded_public_key",
"algorithm": -49
}
]
}'Response:
{
"publicKey": {
"challenge": "dGVzdF9jaGFsbGVuZ2U=",
"rpId": "example.com",
"allowCredentials": [
{
"type": "public-key",
"id": "base64url_encoded_credential_id"
}
],
"timeout": 90000,
"userVerification": "discouraged"
},
"__session_state": "eyJjaGFsbGVuZ2UiOiAi..."
}curl -X POST "https://example.com/api/authenticate/complete?email=user@example.com" \
-H "Content-Type: application/json" \
-d '{
"id": "credential_id",
"rawId": "credential_id",
"response": {
"authenticatorData": "base64_encoded_auth_data",
"clientDataJSON": "base64_encoded_client_data",
"signature": "base64_encoded_signature"
},
"type": "public-key",
"__session_state": {
"challenge": "dGVzdF9jaGFsbGVuZ2U="
}
}'Response:
{
"status": "OK",
"authenticatedCredentialId": "base64url_encoded_credential_id",
"signCount": 123
}