
What is passkey authentication and can websites use it?
Passkey authentication is a way to sign in without a password, using a cryptographic key pair stored on your phone, computer, password manager, or hardware security key. When you log in, your device proves it holds the private key by signing a challenge from the website, and you unlock it with your fingerprint, face, or device PIN. Yes, websites can use passkeys today: they're built on the open WebAuthn standard supported by all major browsers and operating systems, and there are plugins for WordPress and mature libraries for custom applications.
Passwords have been the weak link in website security for decades. They get reused, guessed, phished, and leaked in breaches. Passkeys fix those problems at the root rather than papering over them. This article explains what passkeys are, how they work under the hood, why they're more secure than passwords and most forms of two-factor authentication, and how you can add them to a WordPress site or a custom-built application.
What Is a Passkey?
A passkey is a login credential based on public key cryptography. Instead of a secret that you type and the website stores, a passkey consists of two keys:
- A private key: Stays on your device or in your password manager. It never leaves and is never sent to the website.
- A public key: Stored by the website. It can verify signatures from the private key, but can't be used to create them.
When you sign in, the website sends a random challenge, your device signs it with the private key, and the website checks the signature with the public key. If it matches, you're in. Your device asks you to confirm with biometrics or a PIN first, so someone who picks up your laptop can't just use your passkeys.
Where Passkeys Are Stored
Passkeys can live in several places:
- Platform authenticators: Apple's iCloud Keychain, Google Password Manager, and Windows Hello store passkeys on the device and, in the case of Apple and Google, sync them across your devices.
- Third-party password managers: 1Password, Bitwarden, Dashlane, Proton Pass, and others can store and sync passkeys across platforms.
- Hardware security keys: YubiKey, Google Titan, and similar devices store passkeys on a physical key you plug in or tap.
Synced passkeys are convenient because losing a phone doesn't mean losing access. Device-bound passkeys on hardware keys offer stronger guarantees, which some organisations prefer for administrator accounts.
Passkeys, WebAuthn, and FIDO2
You'll see several terms used together:
- FIDO2: The overall set of standards from the FIDO Alliance for passwordless authentication.
- WebAuthn: The W3C web standard that lets websites use FIDO2 credentials through a JavaScript API in the browser.
- CTAP: The protocol that lets a browser talk to an external authenticator like a security key or your phone.
- Passkey: The user-friendly name for a FIDO2 credential, particularly a discoverable one that can be synced.
For website owners, WebAuthn is the part you'll work with.
How Passkey Authentication Works
There are two ceremonies: registration, when you create a passkey, and authentication, when you use it.
Registration
- The user chooses to create a passkey: Usually from their account settings, or during sign-up.
- The server generates options: This includes a random challenge, the website's identifier (the relying party ID, such as
example.com), and user details. - The browser calls WebAuthn:
navigator.credentials.create()asks the authenticator to generate a new key pair for this site. - The user verifies: A fingerprint, face scan, or PIN confirms the action.
- The server stores the public key: Along with a credential ID and a signature counter, linked to the user's account.
Authentication
- The user clicks sign in: Often they don't even need to type a username.
- The server sends a challenge.
- The browser calls WebAuthn:
navigator.credentials.get()asks the authenticator to sign the challenge. - The user verifies with biometrics or PIN.
- The server verifies the signature with the stored public key and checks that the challenge and origin match. If everything checks out, the user is logged in.
The biometric data never leaves the device. The website only ever receives a signature.
Why Passkeys Are More Secure Than Passwords
They Resist Phishing
This is the biggest advantage. A passkey is bound to the exact domain it was created for. If an attacker builds a perfect copy of your login page at examp1e-login.com, the browser simply won't offer the passkey for example.com. There's nothing for the user to be tricked into typing. Even SMS codes and authenticator app codes can be phished in real time; passkeys can't be phished in the same way.
Nothing Useful to Steal From the Server
If a website's database is breached, attackers get public keys. Those can't be used to log in anywhere, unlike password hashes, which can sometimes be cracked.
No Reuse or Weak Choices
Every passkey is unique to one site and is generated with strong randomness. Users can't pick a weak passkey or reuse the same one across sites.
Credential Stuffing and Brute Force Stop Working
Bots can't guess a private key, and leaked passwords from other sites are irrelevant to a passkey account.
Limitations and Things to Consider
Passkeys are a big improvement, but there are practical points to plan for:
- Account recovery: If a user loses every device with their passkey and has no synced copy, you need a recovery path. That path must be secure too, or attackers will target it instead.
- Cross-ecosystem use: Syncing between Apple, Google, and Microsoft ecosystems has improved, and third-party password managers help, but users on mixed devices may still need to use QR-code cross-device sign-in.
- Shared accounts: Passkeys are designed for individuals. Shared logins don't fit well, which is arguably a good thing.
- User education: Many people still don't know what a passkey is. Clear wording and a gentle rollout help.
- Older devices and browsers: Most modern browsers support WebAuthn, but very old systems may not.
Can WordPress Sites Use Passkeys?
Yes. WordPress core doesn't include passkey login as of WordPress 6.x, but several plugins add it:
- Two Factor (the plugin maintained by WordPress contributors): Supports security keys through WebAuthn-based providers alongside authenticator apps.
- Wordfence Login Security, Solid Security, and miniOrange plugins: Offer passkey or security key support in some editions.
- Dedicated passkey plugins: Several plugins focus specifically on passwordless passkey login for WordPress. Check the plugin's update history, active installs, and support activity before relying on one.
When evaluating a plugin, check that it supports discoverable credentials (true passkeys, not just second-factor keys), that it works with your login URL and any custom login forms, and that it offers a secure fallback.
A sensible rollout for WordPress:
- Start with administrators: They're the highest-value accounts and usually the most willing to try new tools.
- Keep your existing 2FA as a fallback: Until everyone is comfortable, let users choose between passkeys and authenticator apps.
- Register more than one passkey: Encourage admins to add a second passkey, such as one on a phone and one on a hardware key.
- Test recovery: Make sure you know how to regain access if an admin loses their device. Keep a documented break-glass procedure, such as WP-CLI access to reset authentication settings.
Adding Passkeys to a Custom Website
If you run a custom application, you don't need to implement the cryptography yourself. Use a well-maintained WebAuthn library for your stack:
- JavaScript and Node.js: SimpleWebAuthn (
@simplewebauthn/serverand@simplewebauthn/browser). - PHP:
web-auth/webauthn-liborlbuchs/WebAuthn. - Python:
py_webauthn. - Go:
go-webauthn/webauthn. - Java: Yubico's
java-webauthn-server.
Identity platforms such as Auth0, Okta, Microsoft Entra ID, Firebase-compatible providers, Clerk, and Supabase also support passkeys, which can be the simplest route if you already use one.
A Simplified Browser Example
Here's what the browser side of registration looks like with SimpleWebAuthn. The server generates the options and verifies the response:
import { startRegistration } from "@simplewebauthn/browser";
async function registerPasskey() {
// 1. Get registration options from your server.
const optionsResponse = await fetch("/api/passkeys/register/options", {
method: "POST",
credentials: "include",
});
const optionsJSON = await optionsResponse.json();
// 2. Ask the browser and authenticator to create a passkey.
const registrationResponse = await startRegistration({ optionsJSON });
// 3. Send the result back to the server for verification.
const verifyResponse = await fetch("/api/passkeys/register/verify", {
method: "POST",
credentials: "include",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(registrationResponse),
});
const result = await verifyResponse.json();
if (result.verified) {
console.log("Passkey saved.");
}
}
A Simplified Server Example in Node.js
On the server, with Express and SimpleWebAuthn:
import express from "express";
import {
generateRegistrationOptions,
verifyRegistrationResponse,
} from "@simplewebauthn/server";
const app = express();
app.use(express.json());
const rpName = "Example Site";
const rpID = "example.com";
const origin = "https://example.com";
app.post("/api/passkeys/register/options", async (req, res) => {
const user = req.user; // Assumes the user is already logged in.
const options = await generateRegistrationOptions({
rpName,
rpID,
userName: user.email,
attestationType: "none",
excludeCredentials: user.passkeys.map((pk) => ({ id: pk.credentialId })),
authenticatorSelection: {
residentKey: "preferred",
userVerification: "preferred",
},
});
req.session.currentChallenge = options.challenge;
res.json(options);
});
app.post("/api/passkeys/register/verify", async (req, res) => {
const user = req.user;
const verification = await verifyRegistrationResponse({
response: req.body,
expectedChallenge: req.session.currentChallenge,
expectedOrigin: origin,
expectedRPID: rpID,
});
if (verification.verified && verification.registrationInfo) {
const { credential } = verification.registrationInfo;
await savePasskeyForUser(user.id, {
credentialId: credential.id,
publicKey: Buffer.from(credential.publicKey),
counter: credential.counter,
transports: credential.transports,
});
}
req.session.currentChallenge = undefined;
res.json({ verified: verification.verified });
});
savePasskeyForUser is your own function that stores the credential in your database. Library APIs change between major versions, so follow the documentation for the version you install. Authentication works the same way with generateAuthenticationOptions and verifyAuthenticationResponse.
Key Implementation Rules
- Always use HTTPS: WebAuthn only works in secure contexts (HTTPS or localhost).
- Set the relying party ID carefully: It must match your domain or a registrable parent. Passkeys created for
example.comwork on its subdomains, but not on another domain. - Store challenges server-side and use them once: This prevents replay attacks.
- Verify origin and RP ID on every request: Good libraries do this for you if you pass the expected values.
- Let users manage their passkeys: Show a list of registered passkeys with names and creation dates, and let users remove old ones.
- Offer passkey autofill: With conditional mediation, browsers can suggest passkeys directly in the username field, which makes sign-in feel effortless.
Planning a Passkey Rollout
- Offer passkeys as an option first: Add a "Create a passkey" prompt in account settings and after successful logins.
- Measure adoption: Track how many users create passkeys and how often sign-ins succeed.
- Design recovery carefully: Email-based recovery combined with extra verification, backup codes, or support-assisted recovery for high-value accounts.
- Encourage multiple passkeys: Users with a synced passkey plus a backup method rarely get locked out.
- Consider making passkeys the default: Once adoption is healthy, you can make passkeys the primary sign-in method and keep passwords as a fallback, or remove passwords for accounts that have passkeys.
FAQ: Passkey Authentication
Not exactly. A passkey combines something you have (the device holding the key) with something you are or know (biometrics or PIN), so it can replace both a password and a separate second factor in a single step.
No. Biometric checks happen entirely on your device. The website only receives a cryptographic signature proving the private key was used.
If your passkeys are synced through iCloud Keychain, Google Password Manager, or a password manager, they're available on your other devices. Otherwise, you'll need another registered passkey or the site's account recovery process.
Not as of WordPress 6.x. Passkey or security key login currently requires a plugin, such as the Two Factor plugin or a security plugin that supports WebAuthn.
Yes. Passkeys are bound to the domain they were created for, so the browser won't use them on a lookalike phishing site. This is a major advantage over passwords and one-time codes.
Current versions of Chrome, Safari, Firefox, and Edge support WebAuthn and passkeys on major operating systems. Very old browsers and devices may not.
Conclusion
Passkeys are the most meaningful improvement to website login security in years. By replacing shared secrets with public key cryptography, they eliminate password reuse, make database breaches far less damaging, and resist phishing in a way that passwords and one-time codes can't. For users, they're often faster and easier than typing a password.
Websites can use passkeys right now. WordPress site owners can add them through established plugins, starting with administrator accounts, while custom applications can rely on mature WebAuthn libraries or identity providers. Plan your recovery process carefully, encourage users to register more than one passkey, and roll out gradually. Over time, you can move your site closer to a future where passwords are the fallback rather than the front door.


