Understand WebAuthn User ID, User Name, User Display Name, User Handle and Credential ID in Passkey applications and get advice for implementation.
Vincent
Created: December 14, 2023
Updated: October 1, 2024
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.
2. Understanding the WebAuthn Terminology
2.1 What's the WebAuthn Credential ID?
2.1.1 Credential ID of Resident Keys (Discoverable Credentials)?
2.1.2 Credential ID of Non-Resident Keys (Non- Discoverable Credentials)
2.2 What's the WebAuthn User ID (user.id)?
2.3 What's the WebAuthn User Handle (response.userHandle)?
2.4 What's the WebAuthn User Display Name (user.displayName)?
2.5 What's the WebAuthn User Name (user.name)?
2.6 Overview of Storage Requirements and Authenticator Limits?
2.7.1 Can the User ID be Empty or NULL?
2.7.2 Whats the Difference Between User Name and User Display Name in WebAuthn? 2.7.3 How Can I Implement Usernameless / Accountless Authentication?
2.7.4 What Data can be Changed Client-Side (on the Authenticator)?
3. The Complexities and Challenges
3.1 Complications in WebAuthn Specifications (Level 2 vs. Level 3)
3.2 Limit the Number of Credentials Per Authenticator Per Relying Party
3.3 User Handle Should Not Expose Private Information
3.4 Confusing Lookup of Credentials in AllowCredentials
3.5 Confusing UI for User Name and User Display Name when Deleting Passkeys
3.6 How does AllowCredentials work with User ID, User Name or User Display Name?
3.7 How does ExcludeCredentials work with User ID, User Name or User Display Name?
4. Developer Recommendations for Passkey Implementation
4.1 User ID Should Never be an Email Address / Phone Number
4.2 Provide Human-Readable Names Instead of Only Providing Credential IDs for Passkeys
4.3 Leverage User Name as a RP for Differentiating Credentials
4.4 Conditional UI Mostly Uses User Names
Passkeys and the underlying WebAuthn protocol form the new standard of secure and user friendly authentication for web and native apps. To securely and efficiently implement passkeys-based authentication, its of utmost importance to understand the details of user IDs, user names, display names, user handles, and credential IDs in this context. These elements play an important role and can easily be misunderstood causing large efforts to fix them if they were initially implemented the wrong way.
This blog post should help developers and product managers alike to better understand what these specific terms (WebAuthn Credential ID, User ID, User Handle, User Display Name, User Name) mean, how they differ, what makes it challenging and whats the industry-recommended way of implementing them.
Our focus here is not merely on definitions but on the relationships and operational complexities these terms entail. Why is understanding the difference between a 'User Name' and a 'User Display Name' more than an academic exercise? How does the choice of a 'User Handle' affect the privacy and security of your users? These are the questions we aim to answer.
In a field marked by rapid innovation and technical intricacies, staying ahead means not only keeping pace with current trends but also anticipating future developments.
Let's embark on this journey together, unraveling the complexities, understanding the challenges, and embracing the innovations in the world of WebAuthn and passkey applications.
Understanding the different terms is very important. In the following, we explain in more depth and also use a practical example situation to make things more tangible.
Example situation:
Lets say you want to create a new account at a passkey-enabled website. Your real name is John Doe (fullName) and your email address is john.doe@mail.com (loginEmail). The website is accessible at https://www.acme.com and it requires to sign-up with an email address, so that they can send you more emails regarding their product.
Assume that the very simplified backend database would look like this, storing all users in user and all passkeys in passkey table:
In brackets we added which WebAuthn ceremony field corresponds to which database field. Keep in mind that a lot of relevant fields are missing, as this scheme is just to explain the relationship of the most important values: credentialId, user.id, user.name, user.displayName and response.userHandle.
Additionally, the following JSON shows a response during an authentication (login) ceremony that is sent from the authenticator to the relying party:
The WebAuthn Credential ID is a unique ID generated by the authenticator (e.g. your smartphone, laptop or hardware security key like YubiKey) during the registration (sign-up) process of a new credential (passkey). This Credential ID is required for passkey authentication, as it is used to distinguish individual credentials (passkeys). Each Credential ID is exclusive to a specific credential (passkey).
In case of resident-keys (discoverable credentials), the Credential ID is stored by the
authenticator. When a user attempts to
authenticate, the authenticator provides the Credential ID to the relying
party to indicate which credential (passkey) is being used. Moreover,
theres a limit: at most one discoverable credential per User ID (user.id
)
per relying party can be stored.
In case of non-resident keys (non-discoverable credentials), the Credential ID is stored by the relying party server. When a user attempts to authenticate, the user needs to manually select the Credential ID in a dialogue of the relying party. If just one non-resident key is available, this one will be sent to the client.
Example: "5W2vmAU1Mg5vkwzkxRNMdEZwnbrietMwFPdayOdpGkA"
Can it be changed?: No
Pre-defined format: No
Suggested value: Given by authenticator
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 Communityuser.id
)?The WebAuthn User ID (user.id
) is an ID specified by the relying party
(RP) to represent a user account within their system. In the context of
passkeys, the User ID (user.id
) plays a crucial role in linking a
particular user with their credentials (passkeys).
During the registration process, the RP provides the User ID (user.id
) to
the authenticator, which then binds this User ID (user.id
) to the newly
created credential (passkey). This binding is essential for the authenticator
to differentiate between different users credentials (passkeys), especially
in multi-user environments. The User ID (user.id
) should be unique for
each user within the context of the RPs system and is therefore the same
for all registered credentials (passkeys), ensuring a consistent and secure
user identification process throughout the authentication lifecycle.
Example: d2luZG93cyAxMSBjaHJvbWUgMTIw
Can it be changed?: No
Pre-defined format: No
Suggested value: Primary key of user in RPs system (unique ID, UUID, autoinc)
response.userHandle
)?The User Handle (response.userHandle
) , is another critical piece in
passkey authentication. It is chosen by the relying party and is meant to
represent the user account within their system.
The User Handle (response.userHandle
) is returned in the response of the
authenticator which is sent back to the relying party. It is equal to User ID
(user.id). Thats why it is called User ID (user.id
) when the user is
created on the relying party server but when the authenticator responds, it
sets the User Handle (response.userHandle
) to the value of User ID
(user.id).
The User Handle (response.userHandle
) is associated with the credentials
(passkeys) registered by a user and, for resident keys (discoverable
credentials), is stored by the authenticator.
Its primary function is to enable the authenticator to map a set of
credentials (passkeys) to a specific user account. Unlike the Credential ID,
the User Handle (response.userHandle
) is not necessarily unique as
multiple Credential IDs can be associated with the same User Handle
(response.userHandle
).
A secondary use of the User Handle (response.userHandle
) is to allow
authenticators to know when to replace an existing resident key (discoverable
credential) with a new one during the registration ceremony. In this context,
excludeCredentials can be used to prevent the replacement of existing
credentials (passkeys). Specific error messages are shown if the
excludeCredentials list matches any of the locally on the authenticator
available credentials (passkeys). However, even in this matching case, the
WebAuthn registration ceremony is still triggered (meaning that the Face ID,
Touch ID or Windows Hello
popup appears). The reason why this popup appears, even though it fails in the
matching case, is that for privacy reasons, the user needs to successfully
sign the challenge before the authenticator and relying party tell the users
that there is already a credential (passkeys).
Example: d2luZG93cyAxMSBjaHJvbWUgMTIw
Can it be changed?: No
Pre-defined format: No
Suggested value: Primary key of user in RPs system (unique ID, UUID, autoinc)
The WebAuthn User Display Name (user.displayName
) is a user-friendly,
readable name chosen by the user during the registration process. This name is
typically used for display purposes within the application interface and is
not used for authentication.
The primary purpose of the User Display Name (user.displayName
) is to
enhance the user experience by providing a recognizable and human-readable
identifier for the user, which can be their real name, a nickname, or any
other preferred designation. It's important for developers and product
managers to note that the User Display Name (user.displayName
) is for
convenience and personalization and should not be relied upon as a secure
identifier for authentication processes.
It's recommended that the relying party should not restrict the users
choice for User Display Name (user.displayName
) more than necessary.
Example: John Doe
Can it be changed?: Yes
Pre-defined format: No
Suggested value: Full given and family name
user.name
)?The WebAuthn User Name (user.name
) serves to distinguish between user
accounts, particularly in scenarios where multiple accounts might have similar
or identical User Display Names (user.displayName
). It is a unique ID within
the RP's system, and unlike the User Display Name (user.displayName
) , it
is used in the authentication process. The User Name (user.name
) can be an
email address, a specific username, or any other form of unique ID chosen by
the user or assigned by the system.
In the context of passkeys, the User Name (user.name
) is crucial for linking a
specific user account to its credentials (passkeys) and for ensuring the
integrity of the authentication process, especially when dealing with user
accounts that share similar User Display Names (user.displayName
).
User name (user.name
) can be arbitrary strings, not necessarily only email
addresses, phone numbers or usernames.
Example: john.doe@mail.com
Can it be changed?: Yes
Pre-defined format: No
Suggested value: Primary identification (most likely email)
The following table outlines a short summary which storage requirements for the RP database should be taken into account together with the storage limitations of authenticators.
Technically, the WebAuthn specification does not explicitly forbid a NULL
value for user.id (empty values are forbidden though). However, in practice,
it's highly recommended to use a non-NULL User ID (user.id
). This is because
the User ID (user.id
) is intended to uniquely identify a user on the server. A
NULL value would not serve this purpose and could lead to ambiguities or
security issues.
Implications for Resident Keys (Discoverable Credentials):
These are stored on the authenticator and can be used to authenticate a user
without prior knowledge of the User ID (user.id
). However, the User ID
(user.id
) is still important as it allows the server to identify the user once
the Credential ID is presented.
Implications for Non-Resident Keys (Non-Discoverable Credentials):
These require the user to be authenticated first. In this case, the User ID
(user.id
) helps the server to fetch the correct Credential ID and public key
for the user to complete the authentication process and return the Credential
ID.
In summary, while it might be technically possible to have an empty User ID
(user.id
), it is not advisable due to the potential for confusion and security
implications. The User ID (user.id
) plays a crucial role in both discoverable
and non-discoverable credentials, helping to ensure that the right user is
authenticated with the correct credentials.
User Name (user.name
) is typically the user's unique login identifier within
your system (e.g. the email address). This value is crucial for the relying
party (RP) to distinguish between different user accounts.
Contrarily, the User Display Name (user.displayName
) is meant for display
purposes and is more user-friendly. It's often the user's full name or a name
that the user prefers to be addressed by. This is the name shown to the user
in various interfaces, like browser prompts or password managers, making the
authentication experience more personalized and understandable.
Misconfiguration of these values can lead to user confusion or identification
issues. It's important for an RP to accurately configure User Name (user.name)
and User Display Name (user.displayName
) to ensure a seamless user experience.
Incorrect settings might make it challenging to identify the context or the
specific account a passkey is associated with, especially in environments with
multiple deployments or user accounts.
Usernameless / accountless authentication represents a modern approach to user verification that removes the need for traditional usernames. Instead, it relies on cryptographic credentials (passkeys).
To implement usernameless authentication in your system, you need to follow these steps:
response.userHandle
) returned by the authenticator to retrieve the corresponding user account.Changing passkey meta-data on the client side is something that is quite
complex as its not guaranteed that changes are reflected on the server-side
(and vice versa). Especially deleting passkeys on the server-side is not
really propagated to the client-side causing a potentially bad user
experience. Currently, the workaround to change the User Name (user.name) and
/ or User Display Name (user.displayName
) looks like that you create a new
passkey for this relying party with new values for User Name (user.name) and /
or User Display Name (user.displayName
). While doing so you need to make sure
that you use the same User ID (user.id
), which would overwrite the old
passkey.
However, theres a recent WebAuthn explainer that suggests to add new
functions to the WebAuthn API to propagate server-side deleted passkeys to the
client and update User Name (user.name
) as well as User Display Name
(user.displayName
), which is relevant especially in Conditional UI cases. Read more
here.
Become part of our Passkeys Community for updates and support.
JoinThis section delves into these complexities that emerge when implementing passkey based authentication systems and dealing with User IDs, User Names, User Display Names, User Handles and Credential IDs.
The current draft of the Level 3 version also contradicts itself when it comes to the handling of the assertion on the relying party after successful local authentication. These differences in how credentials and user identification are handled can be seen by comparing sections 1.3.3 and 7.2 (6+7) of the WebAuthn Level 3 draft.
1.3.3 Flow:
The server examines the assertion, extracts the Credential ID, looks up the registered credential public key in its database, and verifies the assertion signature.
If valid, it looks up the User ID (user.id
) associated with the assertions
Credential ID. This User ID (user.id
) is now authenticated. The server now
does whatever it would otherwise do upon successful authentication - return a
success page, set authentication cookies, etc.
If the Credential ID is not recognized by the server (e.g., it has been deregistered due to inactivity) then the authentication has failed. Each relying party will handle this in its own way.
7.2 (6+7) Flow:
Its crucial to determine if the user was identified before or not as the two cases differ:
response.userHandle
) of the user account.response.userHandle
) is present. Verify that the user account identified by the User Handle (response.userHandle
) is linked to a credential (passkeys) whose Credential ID equals credential.rawId.As you can see, the big difference between section 1.3.3 and section 7.2 of
the WebAuthn specification is that in 1.3.3 the Credential ID is first used to
query the credential (passkey) table, while in 7.2 the User Handle
(response.userHandle
) is used (especially in case B) to query the user table
before checking the credential (passkey) table.
A critical aspect of WebAuthn is the management of User Handles
(response.userHandle
) and credentials. The WebAuthn RFC 5.4.3 outlines that
authenticators map pairs of relying party IDs and User Handles
(response.userHandle
) to public key credential sources. This mapping dictates
that an authenticator stores only one discoverable credential per User Handle
(response.userHandle
) per Relying Party. The challenge lies in the security
and uniqueness of User Handles (response.userHandle
). Authenticators must know
when to replace an existing discoverable credential with a new one during the
registration ceremony, a process that requires careful handling to maintain
security and user privacy.
Maintaining privacy and security in the WebAuthn framework is paramount. The
User Handle (response.userHandle
), being a key component in the authentication
process, must be handled in a way that it does not reveal private information.
The RFC suggests that User Handles (response.userHandle
) should be unique
account-level identifiers and cautions against using direct hash
transformations of sensitive data, which could lead to security
vulnerabilities.
The Credential ID plays a central role in the authentication ceremony. It is generated by the authenticator and must be unique for each credential. This uniqueness is critical when returning signatures valid for a specific account in an AllowCredentials context. The challenge lies in correctly implementing the lookup mechanism for Credential IDs based on provided identification information (e.g., email or username). This process becomes more intricate when dealing with empty AllowCredentials, where the correct approach involves looking up the Credential ID in the database, then determining login feasibility based on existing or deleted user accounts.
Often the User Name (user.name
) and User Display Name (user.displayName
) in
the browsers or password managers user interfaces do not provide the
context you would need to securely analyze or delete the right passkeys. This
makes it complex for users to distinguish between the right passkeys and can
potentially lead to passkeys being deleted by accident.
AllowCredentials specifies the list of credentials (passkeys) that are allowed to authenticate the user. This list contains Credential IDs that the server is aware of and associates with the user's account. During authentication, the authenticator only returns signatures that are valid for the credentials listed in AllowCredentials. This ensures a secure and specific authentication process, linking the authentication attempt directly to the intended user account.
Changing the User ID (user.id
), User Name (user.name
) or User Display Name
(user.displayName
) does not impact the AllowCredentials process directly. This
is because AllowCredentials focuses on Credential IDs rather than user User ID
(user.id
), User Name (user.name
) or User Display Name (user.displayName
).
ExcludeCredentials is used to prevent the creation of a new credential for a user if that user already has a registered credential on the authenticator. It's a security measure to avoid multiple registrations of the same user on the same device.
ExcludeCredentials contains a list of Credential IDs that are already registered for the user. During the registration process, the authenticator checks this list against the new credential it is about to create. If the new credential's ID matches any in the ExcludeCredentials list, the registration is halted to prevent duplication.
ExcludeCredentials operates on the basis of Credential IDs and does not
directly interact with User ID (user.id
), User Name (user.name
) or User
Display Name (user.displayName
). Its primary function is to check for the
uniqueness of the credential (passkey) being registered, not to validate user
information.
Subscribe to our Passkeys Substack for the latest news, insights and strategies.
SubscribeThe User ID (user.id
) was created to allow the relying party to have control
over how the primary key of the user database looks like. Its considered to
be very bad practice to use anything else than a primary key as User ID
(user.id
), as the User ID (user.id
) never changes in WebAuthn from a technical
point of view. Whereas in reality, its quite a common scenario to have
changing email addresses or phone numbers being reassigned after a
period of inactivity. Therefore, the User ID (user.id
) must never contain any personally identifying information about the user and thus must never be an email address or phone number. Moreover, the User ID (user.id
) must never be empty, though it maybe null. Assigning a non-descript, unique identifier to each user account enhances security and maintains user privacy
Enhancing UX is key when dealing with passkeys. One effective way is to provide human-readable names for these credentials. This allows users to easily distinguish between different passkeys, especially if they have multiple. Here are some specific suggestions:
As highlighted by Matthew Miller, it's recommended for a
Relying Party (RP) to use User Name (user.name) as a unique identifier
(besides User ID). This allows users to easily recognize and manage their
passkeys in various user interfaces. Although some clients and operating
systems might support User Display Name (user.displayName
), its more
reliable to count on the User Name (user.name
) as the identifier regularly
shown to users. This practice ensures consistency across different platforms
and enhances the manageability of credentials.
Implement Conditional UI that supports the User Name (user.name), such as an
email address or username, or other provided identification information to
retrieve potential Credential IDs. This approach is particularly useful in
configuring the AllowCredentials option
in PublicKeyCredentialRequestOptions. Since the exact Credential ID used
for authentication might not be known in advance, using the User Name
(user.name
) as a hint can streamline the authentication process.
As we've navigated the complexities of WebAuthn User ID, User name, User Display Name, User Handle and Credential ID in passkey applications, the importance of the right understanding and correct implementation is clear. We hope that we could have clarified some of the confusing parts. To stay ahead in this rapidly evolving field, feel free to subscribe to our passkeys Substack or join or passkeys community on Slack.
Table of Contents
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
Recent Articles
WebAuthn Relying Party ID (rpID) & Passkeys: Domains & Native Apps
Vincent - September 21, 2023
WebAuthn Conditional UI (Passkeys Autofill) Technical Explanation
Vincent - October 20, 2023