The most surprising thing about passkey cryptography is that it doesn’t actually store a password anywhere. Instead, it relies on a public-key cryptosystem where your device holds a private key, and the service you’re logging into holds the corresponding public key.

Let’s see this in action. Imagine you’re setting up a passkey for a fictional service, "SecureApp."

First, your device (say, your phone) generates a unique pair of cryptographic keys: a private key and a public key. Think of the private key as a super-secret secret you keep on your phone, and the public key as a postcard you send to SecureApp.

On your phone, you’d see something like this (simplified representation):

{
  "privateKeyId": "a1b2c3d4-e5f6-7890-1234-567890abcdef",
  "publicKey": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw... (very long string) ...\n-----END PUBLIC KEY-----"
}

When you initiate passkey creation on SecureApp’s website, your browser communicates with your device’s authenticator (like Face ID, Touch ID, or a PIN). The browser sends a request to the authenticator, which then generates the key pair and securely stores the private key. It then sends the public key to SecureApp’s server. SecureApp stores this public key, associating it with your user account.

Now, for login. When you try to log into SecureApp, instead of asking for a password, it sends a "challenge" – a random piece of data – to your browser.

On SecureApp’s server, this might look like:

{
  "challenge": "some_random_bytes_here_like_jklmnopqrs",
  "rpId": "secureapp.com" // Relying Party ID
}

Your browser receives this challenge and sends it, along with the privateKeyId you want to use, to your device’s authenticator.

Your authenticator then:

  1. Finds the private key associated with privateKeyId.
  2. Uses that private key to cryptographically sign the challenge it received from SecureApp. This signature is unique and proves that the holder of the private key (your device) received the challenge.
  3. Sends this signature back to your browser, which forwards it to SecureApp’s server.

On the server side, SecureApp:

  1. Retrieves your stored public key (which it got during registration).
  2. Uses your public key to verify the signature. If the signature is valid, it means the correct private key was used to sign the challenge, and thus, you are who you say you are.
  3. Logs you in.

The beauty of this is that the private key never leaves your device. It’s used to sign data locally, and only the resulting signature is sent over the network. The public key, which could be shared, is used for verification and cannot be used to forge a signature.

The problem passkeys solve is the inherent insecurity and user friction of passwords. Passwords are often weak, reused, and susceptible to phishing and data breaches. Passkeys eliminate the need for users to remember complex passwords, manage password managers, or be tricked into revealing credentials. They also support strong authentication factors like biometrics, making them significantly more secure.

Here’s the exact mechanism that prevents phishing: when you log in, the authenticator verifies that the rpId (Relying Party ID, e.g., secureapp.com) in the challenge matches the domain you are actually on. If you’re on a fake phishing site that looks like SecureApp but has a different domain (e.g., secureapp-login.scam.com), your authenticator will refuse to use the passkey because the rpId won’t match.

The next concept you’ll encounter is the broader ecosystem of passkey management and synchronization across devices.

Want structured learning?

Take the full Cryptography course →