The Flaws of Shared Secrets & SMS 2FA
For decades, web authentication has relied on shared secrets: passwords stored in databases (hopefully hashed with Argon2 or bcrypt) and shared with the server over TLS. Despite security awareness, password reuse, credential stuffing attacks, phishing kits, and SIM-swapping remain responsible for over 80% of corporate data breaches.
Passkeys—built on the W3C WebAuthn and FIDO2 standards—fundamentally eliminate shared secrets. Instead of sending a password over the wire, authentication uses asymmetric public-key cryptography. The user's device (Apple TouchID, Windows Hello, Android Biometrics, or a hardware YubiKey) generates a unique cryptographic keypair: the public key is stored on your server, while the private key never leaves the device's secure hardware enclave.
1. The WebAuthn Cryptographic Protocol
WebAuthn authentication proceeds through a two-step cryptographic challenge-response exchange:
- Challenge Dispatch: When a user enters their email or username, the server generates a cryptographically random, one-time 32-byte challenge and returns it along with the relying party ID (
rpId = "devmanue.com"). - Hardware Signature: The browser calls the native WebAuthn API:
navigator.credentials.get(). The user touches their fingerprint sensor or FaceID camera. The hardware enclave signs the challenge using the private key. - Cryptographic Verification: The browser returns the signed assertion (authenticator data, client data JSON, and cryptographic signature). The server verifies the signature against the stored public key using standard elliptic curve algorithms (ES256 / Ed25519). If valid, a session is issued.
2. Browser Client Flow: Registering a New Passkey
On the frontend, initiating passkey registration requires zero third-party dependencies; it uses the native browser PublicKeyCredential API:
// Initiate registration from frontend
async function registerPasskey() {
// 1. Fetch challenge from Django backend
const response = await fetch('/api/auth/passkey/register/options/');
const options = await response.json();
// 2. Decode base64url challenge and user ID buffers
options.challenge = Uint8Array.from(atob(options.challenge), c => c.charCodeAt(0));
options.user.id = Uint8Array.from(atob(options.user.id), c => c.charCodeAt(0));
// 3. Prompt user for biometric / hardware credential
try {
const credential = await navigator.credentials.create({ publicKey: options });
// 4. Send public key credential back to server for storage
await fetch('/api/auth/passkey/register/verify/', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
id: credential.id,
rawId: btoa(String.fromCharCode(...new Uint8Array(credential.rawId))),
response: {
clientDataJSON: btoa(String.fromCharCode(...new Uint8Array(credential.response.clientDataJSON))),
attestationObject: btoa(String.fromCharCode(...new Uint8Array(credential.response.attestationObject)))
}
})
});
alert("Passkey successfully registered!");
} catch (err) {
console.error("Passkey registration rejected:", err);
}
}
3. Why Passkeys are Completely Immune to Phishing
The most profound architectural breakthrough of WebAuthn is cryptographic origin binding. When the browser executes navigator.credentials.get(), the operating system itself determines the effective origin (e.g. https://devmanue.com) and passes it directly to the hardware enclave.
If an employee is tricked into visiting a pixel-perfect phishing site like https://devmanue.phishing-clone.com, the browser sends the phishing domain to the security key. The key checks its internal vault, discovers no credential registered for that domain, and refuses to sign. The phisher captures zero credentials because no shared secret exists to steal.
"Passkeys render phishing mathematically impossible. You cannot steal what was never transmitted."
For related production architectures and system implementations, explore these companion guides:
- Enterprise OAuth2 & OIDC PKCE Authentication — Integrate WebAuthn credential registration into enterprise identity provider flows.
- Modern Web Security: Protecting User Privacy — Eliminate credential stuffing and phishing attacks with public-key cryptography.
- End-to-End Type Safety: Django REST with TypeScript & Zod — Validate WebAuthn assertion challenge responses using typed frontend and backend schemas.
Key Architectural Takeaways
Implementing Passkeys transitions your application from legacy shared passwords to asymmetric cryptographic zero-trust authentication. By pairing native browser WebAuthn APIs with robust public-key storage, you deliver instant biometric logins for your users while immunizing your infrastructure against credential stuffing and phishing threats.