Enrollment
Enrollment is the process of registering a new user by connecting their facial biometrics to a Keyless account. During this process, a full and unobstructed view of the user's face is required.
Enrollment with Web SDK can happen in two ways:
Live Enrollment, through the Keyless Web SDK JS libraries described below.
IDV Bridge SaaS, through the Keyless Authentication Service
On this page we'll explain how to perform only interactive live enrollment on the front-end.
Note Keyless also supports component interoperability, so that users could also be enrolled from IDV Bridge OnPremise or the Mobile SDK and still be authenticated via the Web SDK JS at a later date.
Prerequisites
Make sure you have fulfilled the prerequisites listed in the Prerequisites page before going further.
Headless Integration
The @keyless/sdk-web library lets you integrate the Keyless Web SDK however you want in terms of UI/UX, let's see a basic example of enrollment:
import {
addKeylessEventListeners,
createKeylessEnroll,
createKeylessMediaStream,
getKeylessCameraPermissionState,
getKeylessVideoMediaDevices,
getLastKeylessFrameTriggeredBiometricFilters,
importKeylessWebAssemblyModuleOrThrow,
isKeylessVideoMediaStreamAvailable,
KeylessError,
openKeylessWebSocketConnection,
reduceKeylessBiometricFiltersToTriggered,
removeKeylessEventListeners
} from '@keyless/sdk-web'
function requestTransactionJwtVerification(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 enrollment process.
* The error object contains a `code` 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 enrollment symbol.
*/
removeKeylessEventListeners(sym)
// will log the error code
console.error(error.message)
}
/**
* This event is fired when the enrollment process is complete.
* It does not fire for failed attempts, only successful ones.
*/
function onKeylessFinished(sym, message) {
/**
* Removing event listeners is advised on terminal events since
* no more than one attempt is allowed per enrollment symbol.
*/
removeKeylessEventListeners(sym)
/**
* The `transactionJwt` is a JSON Web Token (JWT) that contains information
* about the enrollment 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(message.transactionJwt)
}
/**
* This event is useful for providing real-time feedback to users during
* the enrollment process, such as prompting them to adjust their position
* or lighting conditions to improve biometric recognition.
*/
function onKeylessFrameResults(sym, message) {
let filters
/**
* Returns an array of biometric filters that were triggered in the last frame.
* If no biometric filters were triggered, an empty array is returned.
*/
filters = reduceKeylessBiometricFiltersToTriggered(message.filters)
/**
* Optionally, this function can be used to retrieve the filters that were triggered
* in the last frame.
*
* This can be useful if you need to access the last frame's triggered filters outside
* of the frame results event.
*
* If this function is used then this event is useful for requesting an update to the UI.
*/
filters = getLastKeylessFrameTriggeredBiometricFilters(sym)
}
async function ensureCameraOperativity() {
let devices, state
devices = await getKeylessVideoMediaDevices()
/**
* If the error is MEDIA_DEVICES_NO_VIDEO_INPUTS, it means that
* the user does not have any camera available.
*/
if (devices instanceof Error && devices.message === KeylessError.MEDIA_DEVICES_NO_VIDEO_INPUTS) throw devices
state = await getKeylessCameraPermissionState()
/**
* If the camera permission state is not '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 === KeylessError.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 enrollWithKeyless() {
let enroll, options, stream, open
/**
* Create a Keyless enrollment symbol.
*
* This symbol must be kept in memory for the duration of the enrollment process.
* To perform multiple enrollments, a new symbol must be created for each enrollment.
*/
enroll = createKeylessEnroll()
/**
* Add event listeners through the Keyless enrollment symbol.
* These listeners will handle events during the enrollment process.
*/
addKeylessEventListeners(enroll, [
{ name: 'error', callback: (error) => onKeylessError(enroll, error) },
{ name: 'finished', callback: (message) => onKeylessFinished(enroll, message) },
{ name: 'frame-results', callback: (message) => onKeylessFrameResults(enroll, message) }
])
options = {
customer: { name: 'CUSTOMER_NAME' },
key: { id: 'IMAGE_ENCRYPTION_KEY_ID', value: 'IMAGE_ENCRYPTION_PUBLIC_KEY' },
transaction: {
data: 'DATA_FROM_CUSTOMER_SERVER_TO_BE_SIGNED'
},
username: 'USERNAME',
ws: { url: 'KEYLESS_AUTHENTICATION_SERVICE_URL' }
}
/**
* 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)
/**
* Open a WebSocket connection to the Keyless Authentication Service.
* This connection will be used to process video frames and receive enrollment results.
*/
open = await openKeylessWebSocketConnection(enroll, options)
if (open instanceof Error) return handleOpenKeylessWebSocketConnectionError(open)
}
importKeylessWebAssemblyModuleOrThrow()
.then(() =>
ensureCameraOperativity()
.then(() => enrollWithKeyless())
.catch(handleCameraOperativityError)
)
.catch(handleImportKeylessWebAssemblyModuleError)
Web Component Integration
Now that we have explained how to perform enrollment in a headless way with the @keyless/sdk-web package, here is an example of doing so with common setups:
import '@keyless/sdk-web-components'
export function KeylessEnroll() {
function requestTransactionJwtVerification(jwt) {}
onError = (event) => {
// will log the error code
console.log(event.message)
}
onFinished = (event) => {
/**
* The `transactionJwt` is a JSON Web Token (JWT) that contains information
* about the enrollment 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(message.transactionJwt)
}
return (
<kl-enroll
customer='CUSTOMER_NAME'
enable-camera-instructions
key-id='IMAGE_ENCRYPTION_KEY_ID'
lang='en'
onerror={onError}
onfinished={onfinished}
public-key='IMAGE_ENCRYPTION_PUBLIC_KEY'
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 requestTransactionJwtVerification(jwt) {}
function onError(event) {
// will log the error code
console.log(event.message)
}
function onFinished(event) {
/**
* The `transactionJwt` is a JSON Web Token (JWT) that contains information
* about the enrollment 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(message.transactionJwt)
}
</script>
<template>
<kl-enroll
customer="CUSTOMER_NAME"
enable-camera-instructions
@error="onError"
@finished="onFinished"
key="IMAGE_ENCRYPTION_PUBLIC_KEY"
key-id="IMAGE_ENCRYPTION_KEY_ID"
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>Enroll</title>
<style>
* {
box-sizing: border-box;
}
body {
align-items: center;
display: flex;
justify-content: center;
margin: 0;
min-height: 100vh;
padding: 8px;
}
kl-enroll {
border: 1px solid lightgray;
}
</style>
</head>
<body>
<kl-enroll
customer="CUSTOMER_NAME"
enable-camera-instructions
key="IMAGE_ENCRYPTION_PUBLIC_KEY"
key-id="IMAGE_ENCRYPTION_KEY_ID"
lang="en"
size="375"
theme="light"
transaction-data='DATA_FROM_CUSTOMER_SERVER_TO_BE_SIGNED'
username="USERNAME"
ws-url="KEYLESS_AUTHENTICATION_SERVICE_URL"
></kl-enroll>
<script src="./node_modules/@keyless/sdk-web-components/index.js" type="module"></script>
<script>
const enroll = document.querySelector('kl-enroll')
function requestTransactionJwtVerification(jwt)
enroll.addEventListener('error', (event) => {
// will log the error code
console.log(event.message)
})
enroll.addEventListener('finished', (event) => {
/**
* The `transactionJwt` is a JSON Web Token (JWT) that contains information
* about the enrollment 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(message.transactionJwt)
})
</script>
</body>
</html>Last updated
Was this helpful?