Authentication
Authentication is the biometric equivalent of signing-on. PingOne Recognize compares the user’s current facial biometrics with the ones saved during enrollment.
If the biometrics match, PingOne Recognize authenticates the user.
Before you begin
Make sure you have met the prerequisite requirements before continuing.
Headless integration
The @keyless/sdk-web library lets you integrate the PingOne Recognize Web SDK without using UI controls. Here’s an authentication example:
Details
import {
addKeylessEventListeners,
createKeylessAuth,
createKeylessMediaStream,
getKeylessCameraPermissionState,
getKeylessVideoMediaDevices,
getLastKeylessVideoFrameQuality,
importKeylessWebAssemblyModuleOrThrow,
isKeylessVideoMediaStreamAvailable,
KeylessErrorCode,
removeKeylessEventListeners,
setKeylessDatadogOptions
} from '@keyless/sdk-web'
setKeylessDatadogOptions({ disable: true })
function requestKeylessJwtVerification(jwt) {}
function requestUserCameraPermission() {}
function handleCameraOperativityError(error) {}
function handleImportKeylessWebAssemblyModuleError(error) {}
function handleCreateKeylessMediaStreamError(error) {}
function handleOpenKeylessWebSocketConnectionError(error) {}
/**
* This event is fired when an error occurs during the authentication process.
* The error object contains a `message` property that indicates the type of error.
*/
function onKeylessError(sym, error) {
/**
* Removing event listeners is advised on terminal events since
* no more than one attempt is allowed per authentication symbol.
*/
removeKeylessEventListeners(sym)
// will log the error code
console.error(error.message)
}
/**
* This event is fired when the authentication process is complete.
* It does not fire for failed attempts, only successful ones.
*/
function onKeylessSuccess(sym, message) {
/**
* Removing event listeners is advised on terminal events since
* no more than one attempt is allowed per authentication symbol.
*/
removeKeylessEventListeners(sym)
/**
* The `jwt` is a JSON Web Token (JWT) that contains information
* about the authentication transaction.
*
* This token is signed by the Keyless Authentication Service and can be used
* to verify the authenticity of the transaction.
*
* This operation is strictly backend-to-backend and should never be performed
* in client-side code.
*/
requestKeylessJwtVerification(message.jwt)
}
/**
* This event is useful for providing real-time feedback to users during
* the authentication process, such as prompting them to adjust their position
* or lighting conditions to improve biometric recognition.
*
* The difference with "onKeylessFrameResults" is that this is from filters
* running on the client.
*/
function onKeylessVideoFrameQuality(sym, event) {
/**
* Will log an array of filters that were triggered in this frame.
* If no biometric filters were triggered, an empty array is returned.
*/
console.log(event.filters)
/**
* Optionally, this function can be used to retrieve the quality of the last
* video frame.
*
* This can be useful if you need to access the last video frame quality outside
* of the video frame quality event.
*
* If this function is used then this event is useful for requesting an update to the UI.
*/
console.log(getLastKeylessVideoFrameQuality(sym))
}
async function ensureCameraOperativity() {
let devices, state
devices = await getKeylessVideoMediaDevices()
/**
* If the error is MEDIA_DEVICES_NO_VIDEO_INPUTS, it means that
* the user's device doesn't have a camera.
*/
if (devices instanceof Error && devices.message === KeylessErrorCode.MEDIA_DEVICES_NO_VIDEO_INPUTS) throw devices
state = await getKeylessCameraPermissionState()
/**
* If the camera permission state isn't 'granted', request
* the user to grant camera access.
*/
if (state !== 'granted') {
/**
* Ideally this function should take the user to a UI prompt
* where they can grant camera access to the website.
*
* The easiest way to trigger the browser's camera permission prompt
* is to call isKeylessVideoMediaStreamAvailable(), which will return
* a boolean indicating whether the user granted camera access or not.
*/
requestUserCameraPermission()
throw new Error('camera permission state is not granted')
}
devices = await getKeylessVideoMediaDevices()
/**
* If the error is MEDIA_DEVICES_EMPTY_VIDEO_INPUT_LABEL, it means that
* even though the user has granted camera access, the browser requires
* the user to start a video stream to be able to read the camera labels.
*
* In this case, we perform a throwaway getUserMedia() request with
* isKeylessVideoMediaStreamAvailable() to start a video stream
* to be able to read the camera labels.
*/
if (devices instanceof Error && devices.message === KeylessErrorCode.MEDIA_DEVICES_EMPTY_VIDEO_INPUT_LABEL) {
let available
available = await isKeylessVideoMediaStreamAvailable()
if (!available) throw new Error('video media stream is not available')
devices = await getKeylessVideoMediaDevices()
}
/**
* If we still have an error, throw an error to indicate that
* the media devices still could not be read correctly.
*/
if (devices instanceof Error) throw devices
}
async function authenticateWithKeyless() {
let options, auth, stream, open
options = {
authorization: {
token: 'USER_AUTHORIZATION_FROM_CUSTOMER'
},
customer: { name: 'CUSTOMER_NAME' },
transaction: {
data: 'DATA_FROM_CUSTOMER_SERVER_TO_BE_SIGNED'
},
service: { url: 'KEYLESS_AUTHENTICATION_SERVICE_URL' },
username: 'USERNAME'
}
/**
* Create a Keyless authentication symbol.
*
* This symbol must be kept in memory for the duration of the authentication process.
* To perform multiple authentications, a new symbol must be created for each authentication.
*/
auth = createKeylessAuth(options)
/**
* Add event listeners through the Keyless authentication symbol.
* These listeners will handle events during the authentication process.
*/
addKeylessEventListeners(auth, [
{ name: 'error', callback: (error) => onKeylessError(auth, error) },
{ name: 'success', callback: (message) => onKeylessSuccess(auth, message) },
{ name: 'video-frame-quality', callback: (event) => onKeylessVideoFrameQuality(auth, event) }
])
/**
* Create a media stream from the user's video input media device.
* This stream will be used to capture video frames for biometric analysis.
*
* Note: The user must grant permission to access the media device.
*/
stream = await createKeylessMediaStream()
if (stream instanceof Error) return handleCreateKeylessMediaStreamError(stream)
}
importKeylessWebAssemblyModuleOrThrow()
.then(() =>
ensureCameraOperativity()
.then(() => authenticateWithKeyless())
.catch(handleCameraOperativityError)
)
.catch(handleImportKeylessWebAssemblyModuleError)
Web component integration
This section shows how to use HTML to authenticate.
-
React
-
Vue
-
Embedded
import '@keyless/sdk-web-components'
export function KeylessAuth() {
onError = (event) => {
// will log the error code
console.log(event.message)
}
onSuccess = (event) => {
/**
* The `jwt` is a JSON Web Token (JWT) that contains information
* about the authentication transaction.
*
* This token is signed by the Keyless Authentication Service and can be used
* to verify the authenticity of the transaction.
*
* This operation is strictly backend-to-backend and should never be performed
* in client-side code.
*/
requestTransactionJwtVerification(event.detail.jwt)
}
return (
<kl-auth
authorization-token='USER_AUTHORIZATION_FROM_CUSTOMER'
customer='CUSTOMER_NAME'
enable-camera-instructions
lang='en'
onerror={onError}
onsuccess={onSuccess}
size='375'
theme='light'
transaction-data='DATA_FROM_CUSTOMER_SERVER_TO_BE_SIGNED'
username='USERNAME'
ws-url='KEYLESS_AUTHENTICATION_SERVICE_URL'
/>
)
}
<script setup>
import '@keyless/sdk-web-components'
function onError(event) {
// will log the error code
console.log(event.message)
}
function onSuccess(event) {
/**
* The `jwt` is a JSON Web Token (JWT) that contains information
* about the authentication transaction.
*
* This token is signed by the Keyless Authentication Service and can be used
* to verify the authenticity of the transaction.
*
* This operation is strictly backend-to-backend and should never be performed
* in client-side code.
*/
requestTransactionJwtVerification(event.detail.jwt)
}
</script>
<template>
<kl-auth
customer="CUSTOMER_NAME"
enable-camera-instructions
@error="onError"
@success="onSuccess"
lang="en"
size="375"
theme="light"
transaction-data='DATA_FROM_CUSTOMER_SERVER_TO_BE_SIGNED'
username="USERNAME"
ws-url="KEYLESS_AUTHENTICATION_SERVICE_URL"
/>
</template>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Auth</title>
<style>
* {
box-sizing: border-box;
}
body {
align-items: center;
display: flex;
justify-content: center;
margin: 0;
min-height: 100vh;
padding: 8px;
}
kl-auth {
border: 1px solid lightgray;
}
</style>
</head>
<body>
<kl-auth
customer="CUSTOMER_NAME"
enable-camera-instructions
lang="en"
size="375"
theme="light"
transaction-data='DATA_FROM_CUSTOMER_SERVER_TO_BE_SIGNED'
username="USERNAME"
ws-url="KEYLESS_AUTHENTICATION_SERVICE_URL"
></kl-auth>
<script src="./node_modules/@keyless/sdk-web-components/index.js" type="module"></script>
<script>
const auth = document.querySelector('kl-auth')
auth.addEventListener('error', (event) => {
// will log the error code
console.log(event.message)
})
auth.addEventListener('success', (event) => {
/**
* The `transactionJwt` is a JSON Web Token (JWT) that contains information
* about the authentication transaction.
*
* This token is signed by the Keyless Authentication Service and can be used
* to verify the authenticity of the transaction.
*
* This operation is strictly backend-to-backend and should never be performed
* in client-side code.
*/
requestTransactionJwtVerification(event.detail.jwt)
})
</script>
</body>
</html>