Skip to main content

Authenticate with a credential

Now that we have registered a credential we can use it to authenticate with the Hanko API. The authentication operation is very similar to the registration operation - it's just three simple steps.

The Authentication ceremony#

The authentication ceremony basically corresponds to logging in a user using a previously-registered credential.

  • When a user requests authentication with an existing credential, your relying party application requests generation of credential request options, including a challenge to which the user must respond using a cryptographically signed statement identifying the user.
  • The user provides consent through a local authorization gesture (e.g. through a PIN or biometrics) to use an existing credential's private key to create and cryptographically sign an assertion.
  • The authenticator assertion response is sent to the Hanko Authentication API.
  • The Hanko Authentication API validates the assertion using the stored credential public key.

Step 1: Initialize Authentication at Hanko API#

Just like on registration, the first step to authenticating with a credential is to initialize the authentication ceremony. Initialization consists of retrieving credential request options from the Hanko API in order to trigger the discovery and use of an existing credential on an authenticator for generating an assertion.

Frontend - Trigger authentication initialization#

In your frontend, trigger registration initialization by first making a request to your application backend. To process the request you will need to implement a handler. In this case, we assume your backend handler responds to requests issued to the /webauthn/authentication/initialize endpoint:

const credentialRequestOptions = await fetch('/webauthn/authentication/initialize')

Backend - Retrieve credential request options#

Your backend handler must then issue a POST request to the authentication initialization endpoint of the Hanko API (/v1/webauthn/authentication/initialize - see also the API reference). Unlike in the case of registration, the only user data you need to provide is the user id.

When studying the authentication initialization endpoint description in the API reference you might have noticed

that the user is not required for the operation. In this case, provision of a user is necessary because the credential registered in the previous guide was not registered as a resident key (learn more about resident keys here). :::

Example authentication initialization request body - /v1/webauthn/authentication/initialize
{
"user": {
"id": "e3be22a7-13cf-4235-a09c-380dfd44ac04"
}
}

Just like on registration initialization, you can specify additional options for the authentication operation. For simplicity, this guide will not make use of these options. In a more advanced implementation relying parties can

:::

Step 2: Get credentials and generate assertion#

In order create an assertion and authenticate with an existing credential, your application frontend must pass the credentialRequestOptions obtained in the previous step to the browser through the Web Authentication API. To make things as convenient as possible, you can use the Hanko JavaScript SDK to accomplish this.

import { get as getCredentials } from '@teamhanko/hanko-webauthn'
// Get existing credential and generate an assertion using the credentialRequestOptions from Step 1
const webAuthnResponse = await getCredentials(credentialRequestOptions)

Like on registration, this will trigger a native browser dialog prompting the user to perform an authorization gesture. Once a user has given consent by performing the gesture, the authenticator generates an assertion.

Step 3: Finalize registration with the Hanko API#

The last step is to finalize the authentication with the Hanko API.

Frontend - Forward Web Authentication API response#

Pass the webAuthnResponse from the previous step to your application backend. Again, you will need a corresponding backend handler. Implement a handler that processes requests issued to the /webauthn/authentication/finalize endpoint.

// Finalize the authentication using the `webAuthnResponse` from Step 2
const finalizeResult = await fetch('/webauthn/authentication/finalize', {
method: 'POST',
body: JSON.stringify(webAuthnResponse),
})

Backend - Finalize with the Hanko API#

Finalize the authentication by forwarding the response sent by your frontend to the Hanko API using a POST request to the authentication finalization endpoint (/v1/webauthn/authentication/finalize, see also the API reference).

import (
"github.com/teamhanko/hanko-sdk-golang/webauthn"
"encoding/json"
"net/http"
)
func authenticationFinalizationHandler(w http.ResponseWriter, r *http.Request) {
var request AuthenticationFinalizationRequest
// decode the request body
err := json.NewDecoder(r.Body).Decode(&request)
if err != nil {
// handle error
}
response, apiErr := apiClient.FinalizeAuthentication(request)
if apiErr != nil {
// handle error
}
// return API finalization response
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(data)
}

On successful finalization, the Hanko API returns a representation of the credential used for authentication and the user can be considered logged in.

Congratulations, you successfully authenticated a user using the Hanko API!

Try the example application#

Are you looking for a more immersive learning experience? See how it all works by trying out our example application.