Skip to main content

Usernameless login with resident keys

The Hanko Authentication API allows relying parties to implement usernameless authentication flows by leveraging a WebAuthn feature called resident keys (also client-side discoverable credentials). With resident keys, users no longer need to provide usernames on login, allowing for a more seamless login experience.

Login view mockups showing login with username and login without username
Figure 1: Login view mockups showing login with username (left) vs. login without username (right)

From passwordless to usernameless authentication#

Let us first look at a how passwordless authentication with usernames works and then compare it to usernameless authentication in the following section.

Passwordless authentication#

In the usual passwordless scenario with usernames, authenticators generate and store a credential ID associated with the created credential during registration. The Hanko API stores the public key and credential ID and associates them with a specific user (i.e. via a user ID). During authentication, the relying party identifies the user on whose behalf authentication must be performed and requests authentication with the Hanko API. The Hanko API looks up eligible credentials for this user and passes their credential IDs along to the authenticator.

The following shows an example of a Hanko API authentication initialization response that is then passed along to the Web Authentication API on authentication - observe that eligible credentials including their IDs are specified in the publicKey.allowedCredentials property.

Authentication initialization response including allowCredentials - /v1/webauthn/registration/initialize
"publicKey": {
"challenge": "y4D2TP84tiRKG92hjufmb3u6wB3qq6jEE9qX4MxLDPY",
"timeout": 10000,
"rpId": "hanko.io",
"allowCredentials": [
{
"type": "public-key",
"id": "AVwLDJfbuE9ogiqPbFk..."
}
],
"userVerification": "required"
}

The authenticator then uses the credential ID to identify the correct credential to use for generating an authentication assertion.

Usernameless authentication#

The key feature of resident keys is that, unlike non-resident key credentials, they are discoverable by the authenticator. As a result authentication can be performed without the need of providing credential IDs. Instead, authenticators can discover credentials eligible for authentication based on the relying party's origin (i.e. its rpId) only. The following shows an example of a Hanko API authentication initialization when using resident keys - observe the missing publicKey.allowedCredentials property.

Authentication initialization response without allowCredentials - /v1/webauthn/registration/initialize
{
"publicKey": {
"challenge": "tPkucko8O6qNTtuAPFmAPJtRFUk4q0d5IJxE2btpCbY",
"timeout": 10000,
"rpId": "hanko.io",
"userVerification": "required"
}
}

With resident keys, private key material and all required credential metadata is stored on the authenticator. Because the rpId can be used to identify credentials, relying parties are no longer required to store and look up user identifying information on authentication. This is what essentially enables a usernameless authentication flow.

In order to enable authentication with resident keys credentials must be explicitly created as resident keys on registration.

Registration of a resident key with the Hanko API#

When initializing a registration with the Hanko API, you can indicate your preference regarding creation of resident keys in the request body using the options.authenticatorSelection.requireResidentKey attribute.

Possible values are:

  • true: indicates that the credential should be a resident key.
  • false: indicates that the credential should not be a resident key.
Request resident key on registration initialization - /v1/webauthn/registration/initialize
{
"options": {
"authenticatorSelection": {
"userVerification": "required",
"authenticatorAttachment": "platform",
"requireResidentKey": true
},
"attestation": "direct"
},
"user": {
"id": "e3be22a7-13cf-4235-a09c-380dfd44ac04",
"name": "john.doe@example.com",
"displayName": "John Doe"
}
}
note

Once a credential was registered as resident key, you do not need to provide a user object when initializing an authentication.