Passkeys Authentication

Completes passkey biometric authentication initiated by a login form

Description

This step is used to complete a flow that authenticates the user using WebAuthn biometrics. The biometric credentials must be registered using the Register Passkeys step.

The authentication process starts with a Login Form step that is configured to enable passkeys. Once triggered, this step instructs the client to authenticate passkey credentials on the device. The client does this using the WebAuthn SDK calls, which will prompt the user for biometrics (e.g., fingerprint). If successful, the SDK returns an encoded result. The client submits this result to the journey using the IDO SDK call, and the result is stored in the form output variable.

The journey then proceeds to the passkey branch, which executes the Passkey Authentication step to complete the flow. This step completes the Passkey authentication based on the encoded result obtained from the form (without involving any user interaction). If successful, the journey sets the user context to the authenticated user and continues to the next step. User tokens generated upon authentication can be accessed in subsequent steps using @policy.userTokens(). If it fails, the journey proceeds to a failure branch (if configured); otherwise, the journey is aborted and an error is sent to the client.

To support passkey authentication, you'll need to:

  • Implement passkey registration, as described here
  • Configure the Login Form step, and build the supporting UI
  • Implement the WebAuthn SDK calls required for authentication
  • Implement the IDO SDK call that submits input for the login form step
  • Configure the Passkeys authentication journey step

For more, see the WebAuthn quickstarts (skip the "Complete authentication" section) and see the example below

Configuration

Field Description
Encoded Result WebAuthn encoded result returned by the client to the login form upon successful passkey authentication.
Error Output Variable Name of the variable that contains error data returned by the client
Failure Behavior Determines the behavior in case of failure, which either aborts the journey (default) or proceeds to a failure branch of the control flow.

Example

Consider a login form that authenticates the user using passkeys. In our example, the form ID is loginForm, the input will be stored in a variable named loginData, and only Passkeys is enabled. The passkey branch has the default branch ID (passkeys) and default schema (which expects webauthn_encoded_result from the client).

The passkey branch contains the Passkey Authentication step, which obtains the encoded result from the login form using loginData.webauthn_encoded_result:

When executed, the Login Form step returns the idoServiceResponse object to the client. Based on the form ID passed in journeyStepId, the client presents a form that initiates a WebAuthn authentication process using WebAuthn SDK calls. This will prompt the user to authenticate using biometrics. If successful, the SDK returns the WebAuthn encoded result and the client submits it to the journey to complete the login form step. For example:

JavaScriptKotlinSwift
Copy
Copied
// Authenticates passkey credentials using a modal experience
let authnResult = window.tsPlatform.webauthn.authenticate.modal();

// Submits to the journey the encoded result returned by the WebAuthn SDK call
let nextIdoServiceResponse = await window.tsPlatform.ido.submitClientResponse(
    "passkeys",
    {
        "webauthn_encoded_result": authnResult
    })
Copy
Copied
data class WebAuthnAuthenticationResult(val webauthn_encoded_result: String)
// Expected structure of the data:
// {
//   "webauthn_encoded_result": "passkey authentication result",
// }

// ...
fun authenticatePasskeys(userName: String) {
    TSAuthentication.authenticateWebAuthn(activity.applicationContext, userName, object: TSAuthCallback<AuthenticationResult, TSWebAuthnAuthenticationError> {
        override fun error(error: TSWebAuthnAuthenticationError) {
            // Handle error
        }
    
        override fun success(authResult: AuthenticationResult) {
            // Submits to the journey the encoded result returned by the WebAuthn SDK call
            submitResponse("passkeys", WebAuthnAuthenticationResult(authResult.result()))    
        }
    })
}
Copy
Copied
TSAuthentication.shared.authenticateWebAuthn(username: "[USERNAME]") { result in
    switch result {
    // Submits to the journey the encoded result returned by the WebAuthn SDK call  
    case .success(let response):
        debugPrint("[DEBUG] webauthn_encoded_result: \(response.result)")
        TSIdo.submitClientResponse(clientResponseOptionId: .clientInput,
                                   data: ["webauthn_encoded_result": response.result])
    // Handle error
    case .failure(let error):
        debugPrint("[DEBUG] Error: \(error)")
        TSIdo.submitClientResponse(clientResponseOptionId: .fail)
    }
}

The journey stores the encoded result in the output variable configured for the login form, and proceeds to the Passkey Authentication step. When executed, this step uses the encoded result (loginData.webauthn_encoded_result) to complete the authentication.