Passkeys and WebAuthn: The Future of Authentication Has Arrived
Hello HaWkers, you've probably already seen the "Sign in with Passkey" option appearing on more and more websites. This week, Telegram announced passkeys support, following a trend that is transforming how we authenticate on the web.
Do you still depend on traditional passwords? Let's understand why passkeys are considered the future of authentication and how to implement them in your applications.
What Are Passkeys and WebAuthn
Passkeys and WebAuthn are not competing technologies - they are parts of a system that works together to enable secure passwordless login.
WebAuthn (Web Authentication)
WebAuthn is a standard API developed by the FIDO Alliance and W3C that enables logins without traditional passwords.
Main characteristics:
- Based on public key cryptography
- W3C standard since 2019
- Supported by all modern browsers
- Core component of the FIDO2 project
Passkeys
Passkeys are FIDO authentication credentials that allow login using the same device unlock process.
How they work:
- Use biometrics, PIN or device pattern
- Synced between devices via cloud
- Don't require memorizing passwords
- Resistant to phishing by design
Why Passkeys Are More Secure
Traditional passwords have fundamental security problems that passkeys solve by design.
Password Problems
Common vulnerabilities:
| Problem | Passwords | Passkeys |
|---|---|---|
| Reuse | Common | Impossible |
| Phishing | Vulnerable | Immune |
| Database leak | Data exposed | Only public key |
| Brute force | Possible | Impossible |
| Keyloggers | Vulnerable | Immune |
How Passkeys Protect
1. Domain-bound:
A passkey created for yourbank.com cannot be used on yourbank.fake.com, even if the user is tricked.
2. No shared secret:
The server stores only the public key, which is useless without the private key that never leaves the device.
3. Unique per service:
Each passkey is a unique key pair, so a leak from one service doesn't affect others.
How It Works Technically
Let's understand the registration and authentication flow with WebAuthn.
Registration Flow
// 1. Server generates challenge and options
const publicKeyCredentialCreationOptions = {
challenge: new Uint8Array(32), // Random challenge from server
rp: {
name: "My Application",
id: "mysite.com"
},
user: {
id: new Uint8Array(16), // User's unique ID
name: "user@email.com",
displayName: "User Name"
},
pubKeyCredParams: [
{ alg: -7, type: "public-key" }, // ES256
{ alg: -257, type: "public-key" } // RS256
],
authenticatorSelection: {
authenticatorAttachment: "platform",
residentKey: "required",
userVerification: "required"
},
timeout: 60000
};
// 2. Browser requests credential creation
const credential = await navigator.credentials.create({
publicKey: publicKeyCredentialCreationOptions
});
// 3. Send public key to server to store
await fetch('/api/auth/register', {
method: 'POST',
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)
))
}
})
});
Authentication Flow
// 1. Server sends challenge
const publicKeyCredentialRequestOptions = {
challenge: new Uint8Array(32), // New challenge from server
rpId: "mysite.com",
allowCredentials: [], // Empty for discoverable passkeys
userVerification: "required",
timeout: 60000
};
// 2. Browser requests authentication
const assertion = await navigator.credentials.get({
publicKey: publicKeyCredentialRequestOptions
});
// 3. Send signature for server verification
const response = await fetch('/api/auth/login', {
method: 'POST',
body: JSON.stringify({
id: assertion.id,
rawId: btoa(String.fromCharCode(...new Uint8Array(assertion.rawId))),
response: {
clientDataJSON: btoa(String.fromCharCode(
...new Uint8Array(assertion.response.clientDataJSON)
)),
authenticatorData: btoa(String.fromCharCode(
...new Uint8Array(assertion.response.authenticatorData)
)),
signature: btoa(String.fromCharCode(
...new Uint8Array(assertion.response.signature)
))
}
})
});Practical Implementation
To facilitate implementation, libraries exist that abstract the complexity.
SimpleWebAuthn (Recommended)
// Frontend - @simplewebauthn/browser
import {
startRegistration,
startAuthentication
} from '@simplewebauthn/browser';
// Registration
const registrationOptions = await fetch('/api/webauthn/register-options')
.then(res => res.json());
const registration = await startRegistration(registrationOptions);
await fetch('/api/webauthn/register', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(registration)
});
// Login
const authOptions = await fetch('/api/webauthn/auth-options')
.then(res => res.json());
const authentication = await startAuthentication(authOptions);
await fetch('/api/webauthn/authenticate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(authentication)
});
Backend with Node.js
// Backend - @simplewebauthn/server
import {
generateRegistrationOptions,
verifyRegistrationResponse,
generateAuthenticationOptions,
verifyAuthenticationResponse
} from '@simplewebauthn/server';
// Generate registration options
app.get('/api/webauthn/register-options', async (req, res) => {
const options = await generateRegistrationOptions({
rpName: 'My Application',
rpID: 'mysite.com',
userID: user.id,
userName: user.email,
attestationType: 'none',
authenticatorSelection: {
residentKey: 'required',
userVerification: 'required'
}
});
// Save challenge in session
req.session.challenge = options.challenge;
res.json(options);
});
// Verify registration
app.post('/api/webauthn/register', async (req, res) => {
const verification = await verifyRegistrationResponse({
response: req.body,
expectedChallenge: req.session.challenge,
expectedOrigin: 'https://mysite.com',
expectedRPID: 'mysite.com'
});
if (verification.verified) {
// Save credential in database
await saveCredential(user.id, verification.registrationInfo);
res.json({ success: true });
}
});2025 Updates
The passkeys ecosystem continues to evolve with significant improvements.
WebAuthn Level 3
The WebAuthn Level 3 specification was published as a Working Draft in January 2025, bringing:
- Enhanced APIs for creating and using passkeys
- New security features
- Better cross-device support
NIST Guidelines
NIST will finalize the Digital Identity Guidelines (SP 800-63-4) in July 2025:
- Passkeys recognized as "syncable authenticators"
- Can achieve Authenticator Assurance Level 2 (AAL2)
- Phishing-resistant MFA required for US federal agencies
Passkey Portability
The FIDO Alliance is developing new protocols:
- CXP (Credential Exchange Protocol) - Secure transfer between providers
- CXF (Credential Exchange Format) - Standard exchange format
Platforms with Support
Passkeys are already supported by major platforms.
Sync by Provider
| Provider | Sync | Platforms |
|---|---|---|
| Apple | iCloud Keychain | iOS, macOS |
| Google Password Manager | Android, Chrome | |
| Microsoft | Windows Hello | Windows 10/11 |
| 1Password | App | All |
| Dashlane | App | All |
Service Adoption
Popular services with passkey support:
- Microsoft
- Apple
- Amazon
- GitHub
- PayPal
- eBay
- Nintendo
- Telegram (November 2025)
Implementation Considerations
When adding passkeys to your application, consider these points.
Fallback Required
Not all devices support passkeys. Keep alternative options:
// Check browser support
const supportsWebAuthn = () => {
return window.PublicKeyCredential !== undefined &&
typeof window.PublicKeyCredential === 'function';
};
// Check conditional passkey support
const supportsConditionalUI = async () => {
if (!supportsWebAuthn()) return false;
return await PublicKeyCredential
.isConditionalMediationAvailable?.() ?? false;
};UX Considerations
- Offer passkeys as an option, not mandatory
- Explain benefits to users
- Allow registration of multiple passkeys
- Keep recovery method
Conclusion
Passkeys represent the biggest evolution in web authentication since password popularization. With broad browser and operating system support, intrinsic phishing resistance, and superior user experience, it's the right time to start implementing.
For developers, libraries like SimpleWebAuthn make implementation accessible. For users, the experience is simpler and more secure than traditional passwords.
If you want to deepen your knowledge in web security, I recommend checking out another article: GitHub Actions Pricing Changes 2026 where you'll discover how to protect your CI/CD pipelines.
Let's go! 🦅
💻 Master JavaScript for Real
The knowledge you gained in this article is just the beginning. There are techniques, patterns, and practices that transform beginner developers into sought-after professionals.
Invest in Your Future
I've prepared complete material for you to master JavaScript:
Payment options:
- 1x of $4.90 no interest
- or $4.90 at sight

