developers

I’ve Got Passkeys Working in My App! But How Do I Manage Them?

Passkeys allow you to authenticate securely, and they're easy to integrate using Auth0. But what happens after that? Let's learn how to list and revoke passkeys using Auth0.

Passkeys are the replacement for passwords, and they're here to stay. If you have been learning about this new technology, you know that it's still relatively new, but adoption is growing daily.

Passkeys are available in Auth0, Google, Apple, Github, and many other places. So, there's a chance you are already using passkeys or are starting to implement them.

In this blog post, you'll learn to manage your passkeys in Auth0 using the Management API.

What is a Passkey?

A passkey is a phishing-resistant cryptographic key pair that users can use for passwordless authentication. More specifically, passkeys are FIDO credentials that are discoverable by browsers or housed within native applications or security keys for passwordless authentication.

If you haven't already, you can get started with passkeys using Auth0. After getting your free account, all you need to do is navigate to the Dashboard > Authentication, select your Database Connection, and activate passkeys under the Authentication Methods tab.

passkeys prompt

The Passkey Lifecycle

Let's dive deep into the passkey's lifecycle.

Creation

It all starts by creating a new passkey, and this can happen at different moments throughout the lifecycle of your user account:

  • Create a passkey during the registration flow: When a user signs up for the first time to a website, they can create a passkey for their account.
  • Add new passkey to existing account: Multiple reasons could trigger this scenario; for example, you are starting to roll out passkeys to your users, and when they log in, you prompt them to create a new passkey. Another example is when a user gets a new security key or loses the old one and wishes to create a new passkey in their new device.

When you create a new passkey, your browser will call the

navigator.credentials.create()
method from the Web Authentication (WebAuthn) API. Your authenticator will cryptographically sign a challenge generated by the relying party. You can learn more about the registration process here.

Note that in the creation process, both the authenticator and the relying party, in this case, your server, will persist their records related to the newly created passkey.

Read

When you use your passkey to authenticate yourself, you are "reading" your passkey. Technically speaking, when you use your passkey, the browser calls the

navigator.credentials.get()
method from the Web Authentication API, which is a read endpoint.

In Auth0, you can do this using the Management API, and that's exactly what you'll learn in the next section.

Update

Updating a passkey might be a misleading term; you can't update a passkey itself, but rather, your users can update some attributes that can help them identify their passkeys, such as the display name.

Note that as a developer, you can't update the attributes of a passkey in the relying party, but your end-users can change the display name of their passkeys in their authenticators.

In Auth0, your user's passkeys names might look like something like

passkey|<some_string>
, but this is actually the ID that is also being used as the name.

passkeys list in Auth0 dashboard

Delete

Revoking or deleting a passkey is an action you must execute with extreme care. It's essential that before revoking a passkey, your users have another factor in place to authenticate themselves. Auth0 will still support the password reset flow for this user, which would allow a user to recover access to their account if all their passkeys have been revoked.

Note that because both the relying party and the authenticator have their own record of your passkey when you delete a passkey from the relying party, your users may also have to delete it from their authenticator.

learnpasskeys.io logo

Curious about how passkeys work? Try passkeys now →

learnpasskeys.io

List Passkeys with Auth0

You can see the list of passkeys for a given user using the Auth0 Dashboard, but if you want to retrieve the list to use it in your application, you can use the Auth0 Management API.

Bear in mind you need to enable the use of the Auth0 Management API for your Auth0 Application. You can do so from the Auth0 Dashboard > APIs > Auth0 Management API. Find the Machine to Machine Applications and your Auth0 Application name and toggle the switch to Authorized. You might also need to enable Client-Credentials Exchange.

A passkey in Auth0 is an authentication method, which means you can use the

GET  /api/v2/users/{id}/authentication-methods
endpoint to retrieve passkeys for a given user account. The response of this endpoint looks like this:

[
  {
    "id": "passkey|dev_pzg5wcycfdfd1VZ",
    "type": "passkey",
    "confirmed": true,
    "key_id": "foNlEKGDGREYERxDu3OuXu8sD-rhn1Dsy47HHcwxwg",
    "credential_device_type": "single_device",
    "credential_backed_up": false,
    "identity_user_id": "6657689457685295031f19fb",
    "user_agent": "Chrome 123.0.0 / Mac OS X 10.15.7",
    "public_key": "pQECAyYREGREGRwdnUjPZw9cnElZbv0Q8Axe/NgPBSPmoxJ+86IlggFeeypCWw7eRrgrgrgrrfd5DKYFnarkeoCr6L+1ds4=",
    "created_at": "2024-04-08T15:59:50.762Z",
    "last_auth_at": "2024-04-09T11:35:20.911Z"
  },
  {
    "id": "webauthn-roaming|dev_L7lkgrrgrp4d2x",
    "type": "webauthn-roaming",
    "confirmed": true,
    "name": "carla's key",
    "created_at": "2024-04-26T09:47:15.750Z",
    "last_auth_at": "2024-04-26T09:51:24.089Z",
    "key_id": "O2qqpM1EgSgEaC_NFSOvr0igwNtW91hyGjHNjVCsnjCoLiZzvEvGYOIj_h1SrETGGTRTGRWRk0mmIflkYA",
    "public_key": "pQECAyYgASFYIC9btx34m5xI0Xyr7zpViOVfJQaD2gfDFDDGDFGDFyk2QN6AwjHv1h3Odh+704d8nEbUM1pz+Wf5tyNKTcqg=",
    "relying_party_identifier": "your-tenant.eu.auth0.com"
  }
]

In this case, this user has one passkey and one security key enrolled as their authentication methods. To filter them, you can use the field

type
and check for the
passkey
value.

Here's a code snippet in Ruby that showcases how to call the Auth0 Management API using the

ruby-auth0
gem. You can find a list of all the Management API SDK Libraries here.

# Initialize the Auth0Client
client = Auth0Client.new(client_id: ENV['AUTH0_CLIENT_ID'],
                         client_secret: ENV['AUTH0_CLIENT_SECRET'],
                         domain: ENV['AUTH0_DOMAIN'])

# Call the Get an authentication method by user id endpoint
passkeys = client.user_authentication_methods(auth0_user_id)

# Select only elements that have the type "passkey"
passkeys = passkeys.select { |p| p["type"] == "passkey" }

Where

auth_user_id
is the id of the user in Auth0 (i.e.,
auth0|6657689457685295031f19fb
and the values for
client_id
,
client_secret
, and
domain
are set as environment variables.

The value of the

passkeys
variable would then be:

3.2.2 :010 > passkeys
 => 
[{"id"=>"passkey|dev_pzg5wcycfdfd1VZ",
  "type" => "passkey",
  "confirmed" =>true,
  "key_id"=>"foNlEKGDGREYERxDu3OuXu8sD-rhn1Dsy47HHcwxwg",
  "credential_device_type"=>"single_device",
  "credential_backed_up"=>false,
  "identity_user_id"=>"6657689457685295031f19fb",
  "user_agent"=>"Chrome 123.0.0 / Mac OS X 10.15.7",
  "public_key"=>
   "pQECAyYREGREGRwdnUjPZw9cnElZbv0Q8Axe/NgPBSPmoxJ+86IlggFeeypCWw7eRrgrgrgrrfd5DKYFnarkeoCr6L+1ds4=",
  "created_at"=>"2024-04-08T15:59:50.762Z",
  "last_auth_at"=>"2024-04-09T11:35:20.911Z"}] 
3.2.2 :011 >

Revoke a Passkey in Auth0

Similarly to listing your passkeys, you can use the

DELETE  /api/v2/users/{id}/authentication-methods/{authentication_method_id}
endpoint to revoke a passkey from a user's authentication methods.

Note that before revoking a passkey, you should ensure the user has a fallback authentication factor to allow them to log in. In Auth0, the fallback will automatically be the password reset flow, but you can enable other factors.

Here's an example of how to delete an authentication method using the

ruby-auth0
gem to interact with the Auth0 Management API:

# Instantiate the Auth0Client if it hasn't been instantiated previously
client = Auth0Client.new(client_id: ENV['AUTH0_CLIENT_ID'],
                         client_secret: ENV['AUTH0_CLIENT_SECRET'],
                         domain: ENV['AUTH0_DOMAIN'])

# Call the delete authentication method endpoint 
client.delete_user_authentication_method(auth0_user_id, auth0_passkey_id)

Similarly, here you're reading the values for

client_id
,
client_secret
, and
domain
from the environment; the
auth0_user_id
variable is the user's id in Auth0 and the
auth0_passkey_id
is the passkey's id from Auth0 (i.e.,
passkey|dev_pzg5wcyjfdhgkfSC01VZ
)

Summary

In this blog post, you learned the basics of the passkey's lifecycle and how to list and revoke passkeys using the Auth0 Management API. You also learned that as an end-user, you could create, read, update, and delete passkeys in your authenticators, and as a developer, you can manage the passkey's lifecycle on the relying party's side.