WebAuthn & Passkeys
Deep dive into Signia's passwordless authentication implementation using WebAuthn and Passkeys.
What is WebAuthn?
WebAuthn (Web Authentication) is a W3C standard that enables passwordless authentication using public-key cryptography. It's the underlying technology behind Passkeys.
Key Benefits
- 🔐 Phishing-resistant - Cryptographic proof of origin
- ⚡ Fast - Biometric authentication in seconds
- 🔑 No passwords - Nothing to remember or type
- 🌐 Cross-platform - Works across devices and browsers
- 🔒 Private - Biometrics never leave your device
How It Works
Registration Flow
What happens:
- Server generates a random challenge
- Device creates a new key pair (private + public)
- Private key is stored securely on device (never shared)
- Public key is sent to server and stored
- User proves possession via biometric
Authentication Flow
What happens:
- Server generates authentication challenge
- Device signs challenge with private key
- Signature is sent to server
- Server verifies signature using stored public key
- If valid, user is authenticated
Passkeys vs Traditional WebAuthn
Traditional WebAuthn
- Device-bound - Credential tied to single device
- No sync - Must register each device separately
- Recovery challenge - Lose device = lose access
Passkeys (Modern WebAuthn)
- Synchronized - Credential synced across devices via OS
- Multi-device - Works on all your Apple/Google/Microsoft devices
- Better UX - Seamless cross-device authentication
- Platform support:
- Apple: iCloud Keychain
- Google: Google Password Manager
- Microsoft: Windows Hello
Signia supports both traditional WebAuthn and modern Passkeys. The implementation automatically uses passkeys when available, providing the best possible user experience.
Implementation in Signia
Registration
// Backend generates challenge
POST /register/start
{
"username": "user@example.com",
"display_name": "John Doe"
}
Response:
{
"challenge": "randomBase64String...",
"user": {
"id": "userId",
"name": "user@example.com",
"displayName": "John Doe"
},
"rp": {
"name": "Signia",
"id": "signiaauth.com"
},
"pubKeyCredParams": [
{ "type": "public-key", "alg": -7 } // ES256
],
"timeout": 60000,
"authenticatorSelection": {
"authenticatorAttachment": "platform", // Prefer platform (Face ID/Touch ID)
"residentKey": "preferred", // Enable passkeys
"userVerification": "required" // Require biometric
}
}
// Frontend creates credential
const credential = await navigator.credentials.create({
publicKey: options
});
// Send to backend
POST /register/finish
{
"credential": credential,
"challenge": "originalChallenge"
}
Authentication
// Backend generates authentication challenge
POST /auth/start
{
"username": "user@example.com" // Optional for passkeys
}
Response:
{
"challenge": "randomBase64String...",
"allowCredentials": [
{
"type": "public-key",
"id": "credentialId..."
}
],
"timeout": 60000,
"userVerification": "required"
}
// Frontend gets assertion
const assertion = await navigator.credentials.get({
publicKey: options
});
// Send to backend
POST /auth/finish
{
"assertion": assertion,
"challenge": "originalChallenge"
}
Security Features
Challenge-Response
Every authentication uses a unique challenge:
const challenge = crypto.randomBytes(32); // 32 random bytes
// Challenge is valid for 60 seconds only
Prevents:
- Replay attacks
- Man-in-the-middle attacks
Origin Binding
Credentials are bound to the origin:
rp: {
id: "signiaauth.com",
name: "Signia"
}
Prevents:
- Phishing (credential won't work on fake site)
- Cross-origin attacks
User Verification
Biometric authentication required:
authenticatorSelection: {
userVerification: "required" // Must use biometric
}
Options:
- Face ID (iOS, macOS)
- Touch ID (macOS, iOS)
- Windows Hello (Windows)
- Fingerprint (Android)
Attestation
Verify the authenticator is legitimate:
attestation: "direct" // Request attestation from authenticator
Attestation types:
- None - No attestation
- Indirect - Anonymized attestation
- Direct - Full attestation with device info
Signia uses "none" or "indirect" attestation by default to protect user privacy while maintaining security.
Platform Support
Desktop
| Platform | Browser | Support | Features |
|---|---|---|---|
| macOS | Safari | ✅ Excellent | Touch ID, iCloud Keychain sync |
| macOS | Chrome | ✅ Excellent | Touch ID, Google Password Manager |
| macOS | Firefox | ✅ Good | Touch ID |
| Windows | Edge | ✅ Excellent | Windows Hello, Microsoft sync |
| Windows | Chrome | ✅ Excellent | Windows Hello, Google sync |
| Windows | Firefox | ✅ Good | Windows Hello |
| Linux | Chrome | ⚠️ Limited | USB security keys only |
| Linux | Firefox | ⚠️ Limited | USB security keys only |
Mobile
| Platform | Browser | Support | Features |
|---|---|---|---|
| iOS | Safari | ✅ Excellent | Face ID, Touch ID, iCloud sync |
| iOS | Chrome | ✅ Excellent | Face ID, Touch ID, iCloud sync |
| Android | Chrome | ✅ Excellent | Fingerprint, Google sync |
| Android | Firefox | ✅ Good | Fingerprint |
Credential Types
Platform Authenticators
Characteristics:
- Built into device (Face ID, Touch ID, Windows Hello)
- Cannot be removed or transferred
- Highest security
- Best user experience
Use case: Primary authentication method
Roaming Authenticators
Characteristics:
- Physical security keys (YubiKey, Titan Key)
- Can be used on multiple devices
- Requires carrying physical key
- Excellent for backup
Use case: Backup authentication or high-security scenarios
Security Key Recommendations
Consumer:
- YubiKey 5 Series
- Google Titan Security Key
- Feitian ePass K9
Enterprise:
- YubiKey 5 FIPS
- Feitian A4 FIPS
- Token2 FIDO2 keys
Advanced Features
Resident Keys (Discoverable Credentials)
Enable username-less login:
authenticatorSelection: {
residentKey: "required" // Store credential on device
}
Benefits:
- No need to enter username
- Faster login flow
- Better UX
Requirements:
- Device must support resident keys
- Sufficient storage on authenticator
Multiple Credentials
Users can register multiple credentials:
// User's credentials
[
{
id: "cred1",
type: "platform",
device: "iPhone 13",
created: "2024-01-15"
},
{
id: "cred2",
type: "roaming",
device: "YubiKey 5",
created: "2024-01-20"
}
]
Best practice: Register at least 2 credentials:
- Primary: Device passkey (Face ID/Touch ID)
- Backup: Security key
Credential Management
// List user's credentials
GET /api/credentials
// Revoke a credential
DELETE /api/credentials/:id
// Rename a credential
PATCH /api/credentials/:id
{
"name": "Work iPhone"
}
Testing WebAuthn
Browser DevTools
Chrome DevTools:
- Open DevTools (F12)
- Go to Application tab
- Find WebAuthn section
- Add virtual authenticator
Options:
- Protocol: CTAP2
- Transport: Internal
- Supports resident keys: ✅
- Supports user verification: ✅
Testing Tools
Libraries:
@github/webauthn-json- Simplified WebAuthn API@simplewebauthn/browser- WebAuthn utilitieswebauthn-get- CLI testing tool
Online Testers:
Troubleshooting
"Not allowed" error
Causes:
- User cancelled prompt
- Timeout expired
- Invalid origin
- Browser doesn't support WebAuthn
Solutions:
- Check browser compatibility
- Ensure HTTPS (required)
- Verify origin matches RP ID
Passkey not syncing
iOS/macOS:
- Ensure iCloud Keychain enabled
- Check Apple ID sync settings
- Wait a few minutes for sync
Android:
- Ensure Google Password Manager enabled
- Check Google account sync
- Update Google Play Services
Biometric not working
Checks:
- Biometric enrolled on device
- Biometric permissions granted
- Device supports WebAuthn
- Browser supports user verification
Best Practices
For Users
-
Register multiple credentials
- Primary device
- Backup device
- Security key
-
Keep devices updated
- Latest OS updates
- Latest browser versions
-
Protect your devices
- Use strong device PIN/password
- Enable device encryption
For Developers
-
Always use HTTPS
- Required for WebAuthn
- Use localhost for local dev
-
Set appropriate timeouts
- 60 seconds for registration
- 60 seconds for authentication
-
Handle errors gracefully
- Provide clear error messages
- Offer fallback options
-
Test across platforms
- Different browsers
- Different operating systems
- Different devices
Further Reading
Next Steps
- Security Best Practices - Comprehensive security guide
- Quick Start - Implement authentication
- React SDK - Frontend integration