How do passkeys work

A password sends a secret to the website; a passkey sends proof instead, which the website checks using the public key it saved when you set it up.

HOW PASSKEYS WORK

Animated illustration · No real passkey is created
add a passkey to your account. Illustration: The dragon mascot watches a pretend example.com security settings page marked “already signed in.” A cursor taps “Create a passkey.” A prompt offers a password manager, this device, or a security key, asks for a face, fingerprint, or PIN, then shows “Passkey saved.” You’re already signed in, so the website knows the account is yours. In its security settings you choose “Create a passkey,” pick where to save it, and approve with your face, fingerprint, or device PIN. That check happens on your device; nothing about it is sent to the website.
Scenes
GOOD TO KNOW

Your everyday questions.

Do I need another way to sign in first?

For an existing account, the website must authorize adding a passkey—often after you sign in with your current method. A new account can start with a passkey, without a password. Email verification or identity checks depend on the website. Once set up, a passkey can be your sign-in method; unlocking your device lets you use it.

Where is my passkey saved?

Usually in a password manager, such as Apple Passwords, Google Password Manager, or 1Password. Passkeys can also be saved on the device itself (for example, Windows Hello) or on a physical security key. You choose from the options your device offers when you save it.

What if I lose my phone?

Some passkeys sync: your password manager can make them available on another supported device. Others stay on just one device or security key. For those, you need another sign-in method or the website’s account recovery. Set up a backup before you need it.

Can I use another computer?

Often, yes. Your password manager may make your passkey available there. Some websites also let you sign in using your nearby phone by scanning a QR code. The options depend on your devices and the website.

Does the website get my fingerprint or face?

No. Your device checks your face, fingerprint, or device PIN locally. That gives it permission to use your passkey. The website receives proof that your device has the right key, not your face, fingerprint, or PIN.

How do I get a passkey?

Create one on each website that supports them, either during sign-up or from an existing account’s security settings after signing in. Choose where to save it and approve. Your device or provider creates the keys; the website saves the public part with your account. You do not choose or type a new password.

Do I still need a password?

That depends on the website. Some replace passwords with passkeys; others keep both. Check your sign-in and recovery options before removing a password.

Does this stop every kind of attack?

No. A fake website cannot use the passkey for the real website, but someone could still attack your device, steal an already signed-in session, or abuse account recovery. Passkeys protect an important part of signing in.

Is this demo creating a real passkey?

No. Everything here is a simulation. It does not collect biometric data, save a real passkey, or sign you into an account. Mystic Coders is our example website; this demo does not claim it offers passkey sign-in.

CURIOUS ABOUT THE DETAILS?

What happens at every step

The full explanation: who does what, what gets sent, and what the server checks.

The example above shows what signing in feels like. Here is what happens behind those moments, from creating the passkey to using it on a later visit. This is a written explanation; it does not create a credential or run an authentication request.

First, separate the three jobs.

The website’s server
Also called the relying party. It manages your account, asks for proof, and decides whether a response is valid.
Your browser
Connects the website to the passkey system through WebAuthn, the browser’s authentication API. It knows the page’s actual origin and enforces which website can request which credential.
The authenticator
The part that creates and uses the keys. It may be provided by your device, a password manager, or a physical security key. Your page’s JavaScript does not get access to its private key.

There are two related keys. The private key makes a signature; the public key verifies it. A signature proves that the matching private key was used for particular data. This is not “encrypt with one key and decrypt with the other.” HTTPS separately protects the connection.

Background: MDN’s WebAuthn overview ↗

THE FIRST THREE MOMENTS IN THE EXAMPLE

1. Save a passkey for your account.

For a new account, the website can register a passkey as its first sign-in method; a password is not a WebAuthn requirement. For an existing account, enrollment must be authorized using an existing sign-in or recovery process. Email verification, identity checks, and account recovery are separate decisions made by the website. Approving a local device prompt alone does not establish ownership of an existing account.

  1. The server prepares a registration request.

    For an existing account, it first checks that you are allowed to add a sign-in method. It creates an unpredictable challenge and associates it with this registration attempt. It sends the browser the challenge, website identity, user identifier, supported algorithms, and credential preferences.

  2. The browser asks to create a credential.

    The page calls navigator.credentials.create() with publicKey options. The browser checks the website’s eligibility and lets you choose an available passkey provider.

  3. You approve; the authenticator creates the key pair.

    Your face, fingerprint, or device PIN can authorize the operation locally. The credential is scoped to the website’s relying party ID. The private key stays protected by the authenticator or provider.

  4. The server validates and saves the result.

    The browser returns a credential ID, client data, and an attestation object containing registration information, including the public key. The server verifies the expected challenge, origin, RP ID and required flags, and processes attestation according to policy. It then links the verified credential to the account.

SETUP · BROWSER → SERVER

The public key goes to the website here.

credential ID: kY7p…Q2w
attestationObject → authData
  → credentialPublicKey:
      key type: EC2
      algorithm: ES256
      curve: P-256
      x (hex): 9f2c7a81…
      y (hex): 4b18d6e3…

Illustrative decoded view, with values shortened by …; this is not a complete response or a usable key. The public key is inside the attestation object’s authenticator data, encoded as a COSE key. These labels translate its numeric fields into words. The server extracts and stores it after validating registration.

The two coordinates, x and y, describe this example’s public key. They are safe for the website to receive. The private key is not part of the registration response.

Registration details: Google’s server registration guide ↗

THE NEXT THREE MOMENTS IN THE EXAMPLE

2. Use the saved passkey to sign in.

  1. “Next visit”: request a fresh challenge.

    The server generates a new random challenge for this attempt. It keeps enough state to check the response later. A previously recorded response will not match a fresh challenge. The server must enforce expiration and single use; the browser’s prompt timeout alone does not do that.

    The page calls navigator.credentials.get() with the server’s options. A website can identify an account first and list permitted credential IDs, or let a discoverable passkey identify the account.

  2. “Your device asks for your OK”: select and authorize the key.

    The browser and authenticator locate a credential for the requested relying party. If user verification is required, an appropriate local check must succeed. A touch showing that someone is present and a PIN or biometric check verifying the user are distinct signals.

  3. The authenticator makes the cryptographic proof.

    It signs the authenticator data together with a hash of the browser’s client data. The client data includes the challenge and page origin; authenticator data includes an RP ID hash and flags. That binds the proof to this attempt and website context.

    signature = Sign(privateKey, authenticatorData || SHA256(clientDataJSON))

    Here, || means joining bytes. The private key is used to calculate the signature; it is not included in the response.

  4. “You’re in”: the server verifies before creating a session.

    The browser returns the credential ID, signature, authenticator data, client data and, when provided, user handle. The server looks up the saved public key and checks the signature plus the expected challenge, origin, RP ID and required presence/verification flags. It checks account ownership and processes counters and backup flags according to policy.

    Only after successful verification does the application establish its normal signed-in session. An unresolved, cancelled, expired or invalid response must not sign anyone in.

SIGN-IN · SERVER → BROWSER

A challenge looks like random text.

{
  "challenge": "qGtaOP6qT7LOKxtrsd-koChtLA69XJ9ltWH-sw9r7U8",
  "rpId": "mysticcoders.com",
  "userVerification": "required"
}

A fictional request-options fragment. This full example challenge represents 32 random bytes written as base64url text. Base64url is a way of writing bytes, not encryption. The challenge is not a password or secret; it must be unpredictable and fresh for each attempt.

SIGN-IN · BROWSER → SERVER

The response ties the proof to that challenge.

credential ID: kY7p…Q2w

clientDataJSON (decoded):
{
  "type": "webauthn.get",
  "challenge": "qGtaOP6qT7LOKxtrsd-koChtLA69XJ9ltWH-sw9r7U8",
  "origin": "https://mysticcoders.com",
  "crossOrigin": false
}

authenticatorData (base64url):
  JUCtq-qS…
signature (base64url):
  MEUCIQDx…

Illustrative response fragments, unpacked for reading; … marks shortened values. In JSON transport, binary fields such as clientDataJSON, authenticatorData and signature are commonly base64url strings. Here clientDataJSON is decoded so you can see the same challenge coming back. These fragments are not a valid signed response.

The credential ID tells the server which saved public key to use. Matching the challenge alone is not enough: the server also checks the signature and website context. The public key was saved during setup; it does not need to be sent again for this sign-in. The private key is never sent to the website.

Data formats: Registration public key ↗ · Client data fields ↗.

Protocol checks: WebAuthn assertion verification ↗. Server flow: Google’s authentication guide ↗.

WHY THE LOOKALIKE FAILS

3. Try the same passkey on a fake website.

Our real example uses mysticcoders.com. The unrelated mysticcoders-login.example cannot simply claim that RP ID. The browser validates the request against the actual origin, regardless of the page’s logo or wording.

If the fake page requests a credential for its own domain, it does not get the real site’s credential. If it registers a new key, the real server has not registered that public key for your account. A copied response is also tied to its original challenge and context.

An RP ID is a domain identifier; an origin also includes the scheme and port. Legitimate subdomains can share an eligible parent RP ID, and WebAuthn defines explicit related-origin arrangements. A lookalike spelling alone grants no access.

Passkeys protect this sign-in exchange. They do not fix a compromised device, a stolen session cookie, or weak account recovery.

WebAuthn specification ↗ · FIDO’s passkey overview ↗

CONNECTING THIS TO AN IMPLEMENTATION

Four server operations, plus your account system.

These are illustrative endpoint names, not endpoints implemented by this demo. A WebAuthn library can generate options and verify responses; your application still owns account authorization, challenge lifetime, credential storage, sessions, and recovery.

POST /passkeys/register/options
Authorize enrollment, create a registration challenge, and return creation options.
POST /passkeys/register/verify
Verify the browser’s registration response and save the credential against the authorized account.
POST /passkeys/signin/options
Create an authentication challenge and return request options.
POST /passkeys/signin/verify
Verify the assertion, consume the challenge, update credential metadata, and establish the session.

Browser APIs work with binary data. JSON transport needs suitable encoding and decoding; a browser library can handle that conversion and the WebAuthn calls. Handle cancellation and unsupported environments in the UI. Credential management and recovery need their own application flows.

Implementation references: SimpleWebAuthn server ↗ · SimpleWebAuthn browser ↗ · Complete registration requirements ↗

Back to the start of the detailed explanation ↑

Where you might save a passkey

You may already use one of these password managers. They can save passkeys too.

A physical security key, such as a YubiKey, can also keep passkeys. Those passkeys stay on that key.