Passkeys & WebAuthn – The Complete Guide to Passwordless Authentication in 2026
What Are Passkeys?
Passkeys are the most significant shift in web authentication since the invention of the password. Built on the FIDO2 and WebAuthn standards, passkeys replace traditional passwords with cryptographic key pairs secured by your device's biometric sensor — a fingerprint reader, facial recognition, or a device PIN. You never type a password, never remember a password, and never transmit a secret over the network.
When a user registers with a passkey, their device generates a public-private key pair. The public key is sent to the server and stored alongside the user's account. The private key remains on the device, locked behind the biometric or PIN. During login, the server issues a cryptographic challenge; the device signs it with the private key (after biometric confirmation), and the server verifies the signature with the stored public key. If the signature matches, the user is authenticated. The entire process takes about two seconds and requires no cognitive effort beyond a fingerprint tap or a glance at the camera.
By 2026, Google, Apple, and Microsoft have made passkeys a first-class feature across their platforms. iCloud Keychain syncs passkeys across all Apple devices. Google Password Manager syncs them across Android and Chrome. Windows Hello stores and uses passkeys natively. The result is a passwordless authentication experience that is simultaneously more secure and more convenient than any password-based system.
The Problem with Passwords
To appreciate why passkeys matter, consider the systemic failures of password-based authentication:
Phishing
Phishing remains the number-one attack vector. A convincing email directs the user to a fake login page. The user types their credentials, which are captured by the attacker. No amount of user education has eliminated this risk; as long as the user can enter a password on a fake domain, phishing works.
Credential Stuffing
When a data breach exposes millions of password hashes, attackers use automated tools to test those credentials across other services. Because 65% of users reuse passwords across multiple sites, a single breach cascades into compromise of banking, email, and social media accounts.
Weak Passwords
Despite decades of guidance, users continue to choose predictable passwords. "123456", "password", and "qwerty" top the most-common-passwords list every year. Even password managers, while effective, have adoption rates below 30% among the general population.
Password Fatigue
The average user maintains accounts on over 100 services. Remembering unique, complex passwords for each is unrealistic. This leads to reuse, insecure storage (notes apps, sticky notes), and frequent password resets — which themselves are often exploitable via email account takeover.
Two-Factor Authentication (2FA) Helps, But...
TOTP codes (Google Authenticator) and SMS OTP add a second layer, but they are not phishing-resistant. A real-time phishing proxy can intercept both the password and the OTP as the user enters them. Hardware security keys (YubiKey) solve this but have low consumer adoption due to cost and inconvenience.
Passkeys address all of these problems simultaneously. They are phishing-resistant by design, there is nothing to reuse, nothing to remember, and nothing to intercept.
How Passkeys Work — The Technical Foundation
Public-Key Cryptography
Passkeys are built on asymmetric cryptography. The device generates a key pair:
- Private key — stored securely in the device's hardware-backed keystore (Secure Enclave on Apple devices, TPM on Windows, StrongBox on Android). It never leaves the device.
- Public key — sent to the relying party (your website's server) and stored in the user's account record.
Authentication works like a digital signature: the server presents a challenge, the device signs it with the private key, and the server verifies the signature with the public key. Since only the device possesses the private key, a valid signature proves the user has physical control of the registered device.
Origin Binding
Every passkey is bound to a specific origin (e.g., https://example.com). The browser will not allow a passkey created for example.com to be used on examp1e.com (a phishing domain). This is enforced at the protocol level, making it impossible for phishing sites to request credentials that do not belong to them — regardless of how convincing the fake page looks.
User Verification
Before signing the challenge, the device requires user verification — a biometric check (fingerprint, face) or a device PIN. This ensures that possession of the device alone is not sufficient; the legitimate user must also be present. It is functionally equivalent to two-factor authentication (something you have + something you are) in a single gesture.
The WebAuthn API Explained
WebAuthn (Web Authentication API) is the browser-side standard that enables passkeys. It provides two core methods:
Registration (Creating a Passkey)
const credential = await navigator.credentials.create({
publicKey: {
challenge: new Uint8Array(serverChallenge),
rp: {
name: 'My Website',
id: 'example.com',
},
user: {
id: new Uint8Array(userId),
name: '[email protected]',
displayName: 'Jane Doe',
},
pubKeyCredParams: [
{ alg: -7, type: 'public-key' }, // ES256
{ alg: -257, type: 'public-key' }, // RS256
],
authenticatorSelection: {
authenticatorAttachment: 'platform',
residentKey: 'required',
userVerification: 'required',
},
timeout: 60000,
},
});
// Send credential.response to your server for verification and storage
The browser prompts the user to verify their identity (e.g., Touch ID). On success, it returns a PublicKeyCredential containing the public key and an attestation object that the server can verify.
Authentication (Using a Passkey)
const assertion = await navigator.credentials.get({
publicKey: {
challenge: new Uint8Array(serverChallenge),
rpId: 'example.com',
allowCredentials: [], // empty for discoverable credentials (passkeys)
userVerification: 'required',
timeout: 60000,
},
});
// Send assertion.response to your server for signature verification
With discoverable credentials (the default for passkeys), the allowCredentials array is empty. The browser or platform presents a list of available passkeys for the origin, and the user selects one. This enables a true username-less login flow — the user does not need to type anything.
The FIDO2 Standard
FIDO2 is the umbrella standard that combines WebAuthn (the browser API) and CTAP2 (Client to Authenticator Protocol, for external authenticators like security keys). Together they define the full authentication flow:
- The relying party (your server) generates a challenge and sends registration/authentication options to the client.
- The browser (via WebAuthn) communicates with the authenticator (platform biometric or external security key) via CTAP2.
- The authenticator creates or uses a credential, signs the challenge, and returns the result.
- The browser sends the response to the server, which verifies the signature and completes the operation.
The FIDO Alliance — whose members include Google, Apple, Microsoft, Amazon, Meta, and Visa — governs the standard. By 2026, FIDO2 compliance is a de facto requirement for any authentication system that claims modern security.
Passkeys vs Passwords vs 2FA
| Feature | Passwords | Passwords + TOTP | Passwords + SMS OTP | Passkeys | |---|---|---|---|---| | Phishing resistant | No | No | No | Yes | | Credential reuse risk | High | High | High | None | | Data breach risk | Password hash leaked | Password hash leaked | Password hash leaked | Only public key stored | | User effort | High (remember/type) | Higher (type + code) | Higher (type + wait for SMS) | Minimal (biometric tap) | | Account recovery | Email reset (exploitable) | Backup codes | Email reset | Platform sync + recovery | | Brute-force risk | Depends on password strength | Lower (time-limited code) | Lower (rate-limited) | None (asymmetric crypto) |
Passkeys are superior in every security dimension. The only area where passwords still have an edge is universality — legacy systems and older devices may not support WebAuthn. However, this gap is closing rapidly as platform updates roll out.
Browser and Device Support
As of early 2026, passkey support is effectively universal across modern platforms:
- Chrome (desktop and Android) — full support since version 108.
- Safari (macOS and iOS) — full support since iOS 16 and macOS Ventura.
- Edge — full support via Windows Hello.
- Firefox — full support since version 122.
- Android — Google Password Manager syncs passkeys across all Android devices.
- iOS/iPadOS — iCloud Keychain syncs passkeys across Apple devices.
- Windows — Windows Hello stores passkeys in the TPM.
Cross-device authentication is also standardised: if you need to log in on a device that does not have your passkey, you can scan a QR code with your phone. The phone proves possession of the passkey via Bluetooth proximity, and the desktop browser completes the authentication. This hybrid flow bridges the gap until all devices carry synced passkeys.
Implementation Guide
Server-Side Setup
Your server needs to handle two operations: registration and authentication. Use a battle-tested FIDO2 library rather than implementing the cryptographic verification yourself.
Node.js — use SimpleWebAuthn:
npm install @simplewebauthn/server @simplewebauthn/browser
Registration endpoint:
import {
generateRegistrationOptions,
verifyRegistrationResponse,
} from '@simplewebauthn/server';
app.post('/api/auth/register/options', async (req, res) => {
const user = await getUser(req.session.userId);
const options = await generateRegistrationOptions({
rpName: 'My Website',
rpID: 'example.com',
userID: user.id,
userName: user.email,
userDisplayName: user.name,
attestationType: 'none',
authenticatorSelection: {
residentKey: 'required',
userVerification: 'required',
},
});
req.session.currentChallenge = options.challenge;
res.json(options);
});
app.post('/api/auth/register/verify', async (req, res) => {
const verification = await verifyRegistrationResponse({
response: req.body,
expectedChallenge: req.session.currentChallenge,
expectedOrigin: 'https://example.com',
expectedRPID: 'example.com',
});
if (verification.verified) {
await saveCredential(req.session.userId, verification.registrationInfo);
res.json({ verified: true });
}
});
Authentication endpoint:
import {
generateAuthenticationOptions,
verifyAuthenticationResponse,
} from '@simplewebauthn/server';
app.post('/api/auth/login/options', async (req, res) => {
const options = await generateAuthenticationOptions({
rpID: 'example.com',
userVerification: 'required',
});
req.session.currentChallenge = options.challenge;
res.json(options);
});
app.post('/api/auth/login/verify', async (req, res) => {
const credential = await findCredentialById(req.body.id);
const verification = await verifyAuthenticationResponse({
response: req.body,
expectedChallenge: req.session.currentChallenge,
expectedOrigin: 'https://example.com',
expectedRPID: 'example.com',
authenticator: credential,
});
if (verification.verified) {
req.session.userId = credential.userId;
await updateSignCount(credential.id, verification.authenticationInfo.newSignCount);
res.json({ verified: true });
}
});
Client-Side Integration
import {
startRegistration,
startAuthentication,
} from '@simplewebauthn/browser';
async function registerPasskey() {
const optionsRes = await fetch('/api/auth/register/options', { method: 'POST' });
const options = await optionsRes.json();
const credential = await startRegistration(options);
const verifyRes = await fetch('/api/auth/register/verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(credential),
});
const result = await verifyRes.json();
if (result.verified) {
alert('Passkey registered successfully!');
}
}
async function loginWithPasskey() {
const optionsRes = await fetch('/api/auth/login/options', { method: 'POST' });
const options = await optionsRes.json();
const assertion = await startAuthentication(options);
const verifyRes = await fetch('/api/auth/login/verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(assertion),
});
const result = await verifyRes.json();
if (result.verified) {
window.location.href = '/dashboard';
}
}
Database Schema
Store credentials alongside user accounts:
CREATE TABLE passkey_credentials (
id TEXT PRIMARY KEY,
user_id UUID REFERENCES users(id),
public_key BYTEA NOT NULL,
counter BIGINT NOT NULL DEFAULT 0,
device_type TEXT,
backed_up BOOLEAN DEFAULT FALSE,
transports TEXT[],
created_at TIMESTAMPTZ DEFAULT NOW()
);
UX Considerations
The user experience of passkeys is one of their greatest strengths, but poor implementation can undermine adoption.
Registration Flow
- Offer passkey registration after the user has authenticated via their existing method (password, OAuth). Do not force passkey-only registration on day one.
- Use clear language: "Create a passkey" with a brief explanation like "Log in with your fingerprint or face — no password needed."
- Show a success confirmation with a visual of the biometric used (fingerprint icon, Face ID icon).
Login Flow
- Provide a prominent "Sign in with passkey" button alongside traditional login.
- For returning users with a passkey, auto-trigger the passkey prompt (via conditional UI / autofill) so they do not need to click anything — the browser presents the passkey option directly in the username field.
- Always offer a fallback (password, magic link, OAuth) for users who have not yet registered a passkey or are on a device without their synced credentials.
Passkey Management
- Let users view and delete their registered passkeys in account settings.
- Show device information (name, last used date) so users can identify which passkeys are theirs.
- Allow users to register multiple passkeys (e.g., one on their phone, one on their laptop, one as a hardware key backup).
Security Benefits
Phishing Resistance
The private key is origin-bound. Even if a user visits a perfect clone of your site at a phishing domain, the browser will not find a matching credential. Phishing becomes technically impossible for passkey-protected accounts.
No Secrets on the Server
Your server only stores public keys. If an attacker breaches your database, they obtain public keys that are cryptographically useless for impersonation. There are no password hashes to crack, no salts to harvest.
No Credential Reuse
Each passkey is unique to a specific origin and user. There is no shared secret that could be tested against other websites. Credential stuffing becomes impossible.
Replay Attack Protection
Every authentication includes a unique challenge from the server and a signature counter that increments with each use. Replaying a captured authentication response will fail because the challenge has expired and the counter has advanced.
Protection Against Social Engineering
There is nothing for the user to "tell" an attacker. No password to read over the phone, no OTP to share in a chat. The authentication is physical (biometric + device possession) and cannot be communicated verbally or via text.
Migration from Passwords to Passkeys
Transitioning a user base from passwords to passkeys is a gradual process:
Phase 1 — Offer Passkeys as an Option
Add passkey registration to the account settings page. Promote it with banners and in-app nudges. Users who register passkeys can use either method to log in.
Phase 2 — Passkey-First Login
For users who have registered a passkey, show the passkey prompt first. The password field is available but de-emphasised. Track adoption metrics: what percentage of logins use passkeys?
Phase 3 — Passkey-Preferred
New accounts default to passkey registration. Password creation is still available for users who opt out. Email marketing encourages existing users to register a passkey.
Phase 4 — Passkey-Required (Optional)
For high-security applications (banking, healthcare, enterprise), require passkey authentication and remove password login entirely. Offer hardware security key registration as a backup for users whose devices do not support synced passkeys.
This phased approach ensures that no user is locked out while the ecosystem matures.
Real-World Adoption
Google rolled out passkey support across all Google accounts in 2023. By 2026, passkey logins have surpassed password logins in volume. Google reports that passkey authentication is 40% faster than password + 2FA and has reduced phishing-related account compromises by over 90%.
Apple
Apple integrated passkeys into iCloud Keychain with iOS 16. Every Apple device — iPhone, iPad, Mac — can create and sync passkeys automatically. Safari's autofill UI surfaces passkeys as the primary login option on supported sites.
Microsoft
Windows Hello has supported passkeys since Windows 11 23H2. Microsoft accounts, Azure AD, and Microsoft 365 all accept passkeys. The company is aggressively deprecating password-only authentication for enterprise accounts.
GitHub
GitHub enabled passkey login in 2023 and has since made it the recommended authentication method for developers. Combined with their mandatory 2FA policy, passkeys provide the strongest account protection available on the platform.
E-commerce and Banking
Major e-commerce platforms (Amazon, Shopify stores) and banks (HSBC, ING) have adopted passkeys to reduce checkout friction and meet regulatory security requirements. Passkey login at checkout can increase conversion rates by reducing the drop-off caused by forgotten passwords.
The Future of Authentication
Several trends are shaping the authentication landscape beyond 2026:
- Passkey adoption curve — industry projections suggest that by 2028, passkeys will be the primary login method for over 50% of consumer web traffic.
- Cross-device improvements — Bluetooth proximity verification will become faster and more reliable, making QR-code-based cross-device flows seamless.
- Enterprise SSO integration — identity providers (Okta, Auth0, Microsoft Entra) are adding native passkey support to their SSO flows, enabling passwordless login across all corporate applications.
- Regulatory push — PSD3 in Europe and updated NIST guidelines in the US are moving toward recommending phishing-resistant authentication, which effectively endorses passkeys.
- Credential providers — third-party password managers (1Password, Bitwarden, Dashlane) now store and sync passkeys, extending coverage beyond platform-native solutions.
The password is not dead yet, but its replacement is here, proven, and scaling rapidly. For any new web project started in 2026, passkey support should be part of the authentication strategy from day one.
Conclusion
Passkeys and WebAuthn represent a fundamental improvement in how we authenticate on the web. They eliminate phishing, credential reuse, and password fatigue in a single, user-friendly gesture. The technical foundation is sound (public-key cryptography, origin binding, biometric verification), the tooling is mature (SimpleWebAuthn, platform authenticators), and the ecosystem support is universal (Google, Apple, Microsoft, all major browsers).
If you are building a new application, implement passkeys from the start. If you are maintaining an existing one, begin the migration journey today. Your users will be more secure, your support team will handle fewer "forgot password" tickets, and your login conversion rates will improve.
Need help? Contact us.

