passkeys-cheat-sheetPasskeys Implementation

Passkeys Cheat Sheet for Developers

The developer guide about WebAuthn & implementing passkeys. Download the cheat sheet as a PDF or use this website for all information in one place.

Blog-Post-Author

Lukas R.

Created: March 6, 2024

Updated: October 1, 2024


Download here for free

Free Download

A preview of the cheat sheetDownload the Cheat Sheet as a PDF or continue reading.

Our mission is to make the Internet a safer place, and the new login standard passkeys provides a superior solution to achieve that. That's why we want to help you understand passkeys and its characteristics better.

1. WebAuthn Ceremonies#

Authentication with passkeys is based on the two processes, also called ceremonies, registration(aka the attestation phase) andlogin (aka the assertion phase).
Each phase requires a random challenge generated by the server, which is signed by the authenticator and sent back to the WebAuthn server to verify the user.

Debugger Icon

Want to experiment with passkey flows? Try our Passkeys Debugger.

Try for Free

1.1 Registration (Attestation)#

Process flow of the registration ceremony in WebAuthnThe registration ceremony uses two central objects: PublicKeyCredentialCreationOptions and attestation.

1.2 Login (Assertion)#

Process flow of the login ceremony in WebAuthnThe login ceremony uses two central objects: PublicKeyCredentialRequestOptions and assertion.

Analyzer Icon

Are your users passkey-ready?

Test Passkey-Readiness

2. Important Objects#

For the registration and login with passkeys, there are four main objects:

This section also explains the authenticatorSelection - object, which is used in the PublicKeyCredentialCreationOptions.

Ben Gould Testimonial

Ben Gould

Head of Engineering

I’ve built hundreds of integrations in my time, including quite a few with identity providers and I’ve never been so impressed with a developer experience as I have been with Corbado.

10,000+ devs trust Corbado & make the Internet safer with passkeys. Got questions? We’ve written 150+ blog posts on passkeys.

Join Passkeys Community

2.1 Public Key Credential Creation Options#

PublicKeyCredentialCreationOptions is the central object of the attestation phase (Registration). It is created by and returned from the WebAuthn server.

{ "PublicKeyCredentialCreationOptions": { "rp": { "id": "passkeys.eu", "name": "Corbado Passkeys Demo" }, "user": { "displayName": "john.doe", "id": "dXNyLZ….DU10Tc", "name": "john@doe.com" }, "challenge": "888fix4Bus...pHHr3Y", "pubKeyCredParams": [ { "alg": -7, "type": "public-key" }, { "alg": -257, "type": "public-key" } ], "excludeCredentials": [], "authenticatorSelection": { "authenticatorAttachment": "platform", "residentKey": "required", "userVerification": "required", "attestation": "none", "extensions": [] } } }

The object contains these attributes:

  • rp: Identifies the Relying Party (= the server looking to authenticate the user), see section 4.2 Relying Party ID (rpID).
  • user: Contains data about the user account requesting attestation. The ID is a byte sequence chosen by the Relying Party, that must not contain personal information. The username or e-mail address is saved instead in the name or displayName attribute. Read more about this in section 4.1 Database Schema.
  • challenge: A randomly generated base64URL encoded BufferSource that needs to be signed by the authenticator.
  • pubKeyCredParams: Specified attributes of the credential to be created, usually the supported algorithm(s).
  • timeout: Optional time in milliseconds for the client to wait for the call to complete.
  • excludeCredentials: Optional list of credentials to limit the creation of multiple passkeys on one device.
  • authenticatorSelection: Optional selection of the used authenticator for the method, e.g. whether a residentKey is required. See 2.5 authenticatorSelection.
  • attestation: Can be used to request that the attestation object is passed on to the Relying Party in a specific form. Possible values are none (default), indirect, direct and enterprise.
  • extensions: Optional request(s) for additional processing, such as specific return values. e.g.
    • credProbs requests information on whether the created credential is discoverable
    • prf allows the Relying Party to use outputs from a pseudo-random function (PRF) associated with a credential
Substack Icon

Subscribe to our Passkeys Substack for the latest news, insights and strategies.

Subscribe

2.2 Public Key Credential Request Options#

PublicKeyCredentialRequestOptions is the central object of the assertion phase (Login). It is created by and returned from the WebAuthn server.

{ "publicKeyCredentialRequestOptions": { "challenge": "pT7HMA-…dFPHk", "timeout": 500, "rpId": "passkeys.eu", "userVerification": "preferred", "allowCredentials": [], "extensions": [] } }

The object contains these attributes:

  • challenge, timeout, extensions: see above.
  • rpId: The identifier of the Relying Party for the assertion request, see section 4.2 Relying Party ID (rpID).
  • allowCredentials: Optional list of credentials that are allowed for authentication, indicating the callers preference by descending order. This list would be filled with PublicKeyCredentialDescriptors.
  • userVerification: Optional value to specify requirements for user verification during the operation. Possible values are preferred (default), required or discouraged.

2.3 Attestation#

During the Attestation / Registration Ceremony, the Authenticator returns this Registration Response. You can try this yourself in the Passkeys Debugger.

{ "authenticatorAttachment": "platform", "id": "JKZbixUfKN_aZtimefYT-OjH5dw", "rawId": "JKZbixUfKN_aZtimefYT-OjH5dw", "response": { "attestationObject": { "fmt": "none", "attStmt": {}, "authData": { "rpIdHash": "PpZrl-Wqt-OFfBpyy2SraN1m7LT0GZORwGA7-6ujYkM", "flags": { "userPresent": true, "userVerified": true, "backupEligible": true, "backupStatus": true, "attestedData": true, "extensionData": false }, "counter": 0, "aaguid": { "raw": "fbfc3007-154e-4ecc-8c0b-6e020557d7bd", "name": "iCloud Keychain" }, "credentialID": "JKZbixUfKN_aZtimefYT-OjH5dw", "credentialPublicKey": "pQECAyYgASFYIPWLalDzyxIDmAADvfK8iNM5To50kh7TyPH-teEz8RMdIlgg3D7bPIWQJ8z-WFn3zdYZzJw9c7mhPdmflQqD9vV7efA", "parsedCredentialPublicKey": { "keyType": "EC2 (2)", "algorithm": "ES256 (-7)", "curve": 1, "x": "9YtqUPPLEgOYAAO98ryI0zlOjnSSHtPI8f614TPxEx0", "y": "3D7bPIWQJ8z-WFn3zdYZzJw9c7mhPdmflQqD9vV7efA" } } }, "clientDataJSON": { "type": "webauthn.create", "challenge": "k2p6f-upzP_hc6NZvmMAxiI0VSTeQIeXXVRGW62LTj0", "origin": "https://www.passkeys-debugger.io", "crossOrigin": false }, "transports": [ "hybrid", "internal" ], "authenticatorData": "PpZrl-Wqt-OFfBpyy2SraN1m7LT0GZORwGA7-6ujYkNdAAAAAPv8MAcVTk7MjAtuAgVX170AFCSmW4sVHyjf2mbYpnn2E_jox-XcpQECAyYgASFYIPWLalDzyxIDmAADvfK8iNM5To50kh7TyPH-teEz8RMdIlgg3D7bPIWQJ8z-WFn3zdYZzJw9c7mhPdmflQqD9vV7efA", "publicKey": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE9YtqUPPLEgOYAAO98ryI0zlOjnSSHtPI8f614TPxEx3cPts8hZAnzP5YWffN1hnMnD1zuaE92Z-VCoP29Xt58A", "publicKeyAlgorithm": -7 }, "type": "public-key", "clientExtensionResults": {} }

The attestation contains some important components like attestationObject, algorithm and the transport-flags.

2.3.1 attestationObject#

The attestationObject is part of the attestation in WebAuthn

Taken from W3C's Webauthn specification

The attestationObject is a CBOR-encoded object, containing information about the newly created credentials, the public key and other relevant data:

  • fmt is typically evaluated to "none" for passkeys
  • attStmt is empty for passkeys and filled for other authenticators, e.g. hardware security key
  • authData is a buffer of values containing the following data:

authData is a buffer of values, containing e.g. flags, counters and extensions

Read more about the extensions.

algorithm

Passkeys are generated with COSE algorithms, indicating the used algorithm in the algorithm-attibute of parsedCredentialPublicKey in the attestation object.
Here's an overview of the most relevant COSE algorithms:

Passkeys are generated with COSE algorithms

2.3.2 transport#

The transports -property indicates mechanisms through which an authenticator can communicate with a client. Some common, sample value combinations are:

2.4 Assertion#

During the Assertion / Login Ceremony, the Authenticator returns this Login Response. You can try this yourself in the Passkeys Debugger.

{ "id": "JKZbixUfKN_aZtimefYT-OjH5dw", "rawId": "JKZbixUfKN_aZtimefYT-OjH5dw", "type": "public-key", "authenticatorAttachment": "platform", "response": { "authenticatorData": { "rpIdHash": "PpZrl-Wqt-OFfBpyy2SraN1m7LT0GZORwGA7-6ujYkM", "flags": { "userPresent": true, "userVerified": true, "backupEligible": true, "backupStatus": true, "attestedData": false, "extensionData": false }, "counter": 0 }, "clientDataJSON": { "type": "webauthn.get", "challenge": "GCVkITWbe2l2dttsn_DgJYvH9QPHPDo0ygWgcgI6B7U", "origin": "https://www.passkeys-debugger.io", "crossOrigin": false, "other_keys_can_be_added_here": "do not compare clientDataJSON against a template. See https://goo.gl/yabPex" }, "signature": "MEQCIA-orC8N2KKWOxyY17BWP8lB-Be5to9btXRnJZf2SLhXAiBGxJe5Eu5LwOTbsyzAYmIXHOhlC3pN7s7Q1fRLvEW57g", "userHandle": "_FKz1uwqmR_3yGq6hJntzoIFwFC_d1u_53YRELh0KlE" } }

The assertion contains some important components like flags, signature and userHandle.

2.4.1 flags#

Here's an overview of the most relevant flags and their combinations:

The most important flags are userPresent, userVerified, backupEligible, backupStatus

2.4.2 signature#

The signature is used to verify that the user trying to log in, actually has the private key. The signature is created by concatenating the authenticatorData and clientDataHash (i.e. the SHA-256 version of ClientDataJSON) and signing the result with the private key (in the authenticator). To verify with the public key, we concatenate authenticatorData and clientDataHash as well. If the verification result returns true, the authentication is successful.

The signature is used to verify the private key

2.4.3 userHandle#

The userHandle is the actual user_id. Read more about the user_id in section 4.1 Database Schema.

2.5 authenticatorSelection#

The authenticatorSelection - object allows the server to dictate¨settings for the authenticator and credential creation with the following values:

2.5.1 authenticatorAttachment#

  • Platform: The authenticator is attached to the client's platform and is therefore not removable.
  • Cross-platform: The authenticator is not bound to the client's platform and can be used on multiple devices.

2.5.2 residentKey#

  • Required: The authenticator must create a resident key (if not possible the operation should fail).
  • Preferred: The authenticator should try to create a resident key (if not possible it should create a non-resident key).
  • Discouraged: The authenticator must create a non-resident key (if not possible the operation should fail).

Resident Keys (also called Discoverable Credential): Resident keys are stored on the authenticator and retrieved during authentication. ¨This way the client can discover a list of possible keys, which is why [Conditional UI](/blog/user-transition-passkeys-> conditional-ui) requires resident keys. Non-Resident Keys (also called Non-Discoverable Credential): In case of non-resident keys, the credential ID is stored on the server and not on the authenticator. During each authentication, the authenticator derives the private key from a seed within the credential ID and an internal master key that is saved on the authenticator.

2.5.3 userVerification#

  • Required: The operation should verify the user.
  • Preferred: The operation should verify the user, but can proceed without it (standard option)
  • Discouraged: The operation should not verify the user.

Warning: If set to "Preferred", the user or his device can skip the user verification in the authentication process (read more in this article).

Slack Icon

Become part of our Passkeys Community for updates and support.

Join

3. Conditional UI#

Conditional UI (passkey autofill) displays available passkeys in a selection dropdown for the user, when a user has a resident key registered with the relying party. ¨It improves the usability of passkeys, but requires additional development efforts and is not available for all OS / browser combinations.

3.1 Login Flow with Conditional UI#

Process flow of a login with Conditional UI in WebAuthnLike a regular login, Conditional UI also uses the objects PublicKeyCredentialRequestOptions and assertion

3.2 Device Compatibility#

Conditional UI is not available on all combinations of operating systems and browsers (yet). Here's an overview of the current browser coverage (March 2024):

Table that shows the availability of Conditional on OS/browser combinations

For an up-to-date overview see this website.

3.3 Code Examples#

3.3.1 Conditional UI Method#

A full, minimalistic code for a Conditional UI method looks like this:

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Conditional UI</title> </head> <body> <input type="text" id="username" autoComplete="username webauthn" /> <script> async function passkeyLogin() { try { // retrieve the request options (incl. the challenge) from the WebAuthn server let options = await WebAuthnClient.getPublicKeyRequestOptions(); const credential = await navigator.credentials.get({ publicKey: options.publicKeyCredentialRequestOptions, mediation: "conditional", }); const userData = await WebAuthnClient.sendSignedChallenge(credential); window.location.href='/logged-in'; } catch (error) { console.log(error); } }; passkeyLogin(); </script> </body> </html>

3.3.2 Browser Compatibility Check#

Conditional UI only works with resident keys / discoverable credentials
Its recommended to provide a different server endpoint to start the Conditional UI login.
The client needs to meet multiple requirements:

  • The browser needs to support Conditional UI (see 3.2 Device Compatibility).
  • JavaScript must be enabled and the web page must provide an HTML input field.
  • Timeout parameters should be disregarded

To avoid errors, the server should first test the clients availability with this function:

// source: https://developer.mozilla.org/en-US/docs/Web/API/PublicKeyCredential/isConditionalMediationAvailable#examples // Availability of `window.PublicKeyCredential` means WebAuthn is usable. if ( window.PublicKeyCredential && PublicKeyCredential.isConditionalMediationAvailable ) { // Check if conditional mediation is available. const isCMA = await PublicKeyCredential.isConditionalMediationAvailable(); if (isCMA) { // Call WebAuthn authentication start endpoint let options = await WebAuthnClient.getPublicKeyRequestOptions(); const credential = await navigator.credentials.get({ publicKey: options.publicKeyCredentialRequestOptions, mediation: "conditional", }); /* ... */ } }

3.3.3 Autocomplete Token in Input Fields#

The input field should receive an HTML autofill token, that signals the client to populate passkeys to the ongoing request. Besides passkeys, the autofill tokens can be paired with existing tokens, e.g. usernames and passwords:

  • autocomplete="username webauthn": Besides displaying passkeys, this also suggests username autofill.
  • autocomplete="current-password webauthn": Besides displaying passkeys, this further prompts for password autofill.
<label for="name">Username:</label> <input type="text" name="name" autocomplete="username webauthn"> <label for="password">Password:</label> <input type="password" name="password" autocomplete="current-password webauthn">

4. WebAuthn Server#

4.1 Database Schema#

There is no mandatory or standardized database schema for WebAuthn servers. ¨However, this example database schema can be used to store the required information and provide all functionalities of a WebAuthn server:

Bold attributes are mandatory for a minimal viable implementation, while the others are only needed for optional, but helpful features.

4.1.1 Authentication-relevant data#

  • Credential ID: This is a unique ID thats generated by the authenticator during registration of a passkey. It should be used to look up the actual user account thats associated with the passkey. ¨Additionally the userHandle (from user_id) should then be compared to validate the account used for authentication. Dont use the user.name attribute for comparison as it can change over time.
  • User ID (user_id): Unique ID specified by the Relying Party to represent a user account in their system. Its returned as the userHandle within the assertion-object.

4.1.2 Metadata for display and selection of passkeys:#

  • User DisplayName (user.displayName): User-friendly, readable name that is typically the full name of the user. ¨Its shown to the user, but not used during authentication.

  • User Name (user.name): Unique and readable name that is typically an e-mail address or a username. It can be shown to the user, but it's not used during authentication.

4.2 Relying Party ID (rpId)#

The Relying Party ID (rpID) is a domain stored within the passkey, ensuring the passkey only works for the correct domain (browser URL, see this article for native apps). During authentication, the rpID is checked against the browser URL and only allowed in these two cases:

  1. The URL matches precisely the rpId OR
  2. The URL is a subdomain that matches the rpId and the parent domain is not on the Public Suffix List

Here are examples for (dis-)allowed combinations:

Examples for allowed and disallowed combinations of Relying Party IDs

5. Helpful Websites and Tools#

Here's a list of useful tools & websites for implementing passkeys.

  • Passkeys Debugger: Tool for debugging the WebAuthn Responses as JSON and testing WebAuthn operations with different options.
  • Passkeys Glossary: Explanation of passkey-related terms & concepts
  • WebAuthn Specification: This is the official WebAuthn specification.
  • Chrome Device Log: Tool for showing a log of your device's WebAuthn operations (only avaible on Chrome via chrome://device-log)

If you want to implement passkeys with just a few lines of code into any application, you can also use Corbado Complete (for new apps) or Corbado Connect (for existing apps)

Share this article


LinkedInTwitterFacebook

Enjoyed this read?

🤝 Join our Passkeys Community

Share passkeys implementation tips and get support to free the world from passwords.

🚀 Subscribe to Substack

Get the latest news, strategies, and insights about passkeys sent straight to your inbox.


We provide UI components, SDKs and guides to help you add passkeys to your app in <1 hour

Start for free