1# Facial Authentication 2 3## Overview 4 5### Function 6 7Facial authentication provides user authentication capabilities in identity authentication scenarios, such as device unlocking, payment, and app logins. It uses biometric recognition technologies to identify individuals based on facial characteristics. A camera is used to collect images or video streams that contain human faces, and automatically detect, track, and recognize human faces. Facial authentication is also called facial recognition. The figure below shows the architecture of facial authentication. 8 9The face authentication (Face_auth) driver is developed based on the Hardware Driver Foundation (HDF). It shields hardware differences and provides stable facial authentication capabilities for the user authentication framework (User_auth) and Face_auth service. The facial authentication capabilities include obtaining facial recognition executor list, executor information, and template information by template ID, comparing face image template information of the executor and that of User_auth, enrolling or deleting face images, and performing facial authentication. 10 11**Figure 1** Facial authentication architecture 12 13 14 15### Basic Concepts 16 17The identity authentication consists of User_auth and basic authentication services (including PIN authentication and facial authentication). It supports basic functions such as setting and deleting user credentials and performing authentication. The system supports user identity authentication and data collection, processing, storage, and comparison. 18- Executor 19 20 The executor collects, processes, stores, and compares data for authentication. Each authentication service provides the executor capabilities, which are scheduled by User_auth to implement basic capabilities. 21 22- Executor security level 23 24 Security level of the runtime environment when an executor provides capabilities. 25 26- Executor role 27 28 - Executor: independently completes the entire process of credential registration and identity authentication. The executor can collect, process, store, and compare data to complete the authentication. 29 30 - Collector: only collects data during user authentication. It needs to work with the authenticator to complete user authentication. 31 32 - Authenticator: only processes data, obtains the stored credential template, and compares it with the authentication information generated. 33 34- Executor type 35 36 The authentication algorithm varies depending on the authentication mode and device used. Different executor types are defined based on the supported algorithm type or the device in use. 37 38- User_auth public key & executor public key 39 40 To ensure user data security and authentication result accuracy, measures must be taken to protect the integrity of the key information exchanged between User_auth and basic authentication services. Public keys must be exchanged when the executor provided by a basic authentication service interworks with User_auth. 41 42 The executor uses the User_auth public key to verify scheduling instructions. 43 44 User_auth uses the executor public key to verify the authentication result accuracy and the integrity of the information exchanged with the executor. 45 46- Authentication credential template 47 48 Authentication credentials are generated and stored by the authentication service when users set authentication credentials. Each template has an ID to index a set of template information files. The template information needs to be compared with the authentication data generated during authentication to complete identity authentication. 49 50- Data verification by the executor 51 52 User_auth manages the mappings between user identities and credential IDs in a unified manner. When connecting to User_auth, the executor obtains the template ID list from User_auth and updates its template ID list based on the template ID list obtained. 53 54- HAPs 55 56 In a broad sense, OpenHarmony Ability Packages (HAPs) are application packages that can be installed on OpenHarmony. In this document, the HAPs only refer to the upper-layer applications of the Face_auth driver. 57 58- IDL interface 59 60 An Interface Definition Language (IDL) is a language that lets a program or object written in one language communicate with another program written in an unknown language. An IDL compiler generates client stub files and server framework files. This document describes how to use the client and server generated by the IDL interface to implement communication between the Face_auth service and driver. For details, see [IDL](https://gitee.com/openharmony/ability_idl_tool/blob/master/README.md). 61 62- IPC 63 64 Inter-process communication (IPC) is a mechanism that allows processes to communicate with each other. For details, see [IPC](https://gitee.com/openharmony/communication_ipc/blob/master/README.md). 65 66- HDI 67 68 The hardware device interface (HDI) is located between the basic system service layer and the device driver layer. It provides APIs for abstracting hardware device functions, which shields underlying hardware device differences for system services. For details, see [HDI Specifications](../../design/hdi-design-specifications.md). 69 70### Working Principles 71 72The Face_auth driver provides basic facial authentication capabilities for the User_auth and Face_auth service to ensure successful facial authentication. 73You can develop drivers to call Hardware Device Interface (HDI) APIs based on the HDF and the chip you use. 74 75**Figure 2** Face_auth service and Face_auth driver interaction 76 77 78 79### Constraints 80 81- To implement facial authentication, the device must have a camera and the face image must be greater than 100 x 100 pixels. 82- A Trusted Execution Environment (TEE) must be available, and facial feature information must be encrypted and stored in a TEE. 83- The face matching accuracy varies with people with similar looks and children whose facial features keep changing. If you are concerned about this, consider using other authentication modes. 84 85## Development Guidelines 86 87### When to Use 88 89The Face_auth driver provides basic facial authentication capabilities for the User_auth and Face_auth service to ensure successful facial authentication. 90 91### Available APIs 92 93The following table describes the C++ APIs generated from the Interface Definition Language (IDL) interface description. For details about the interface declaration, see the .idl file in **/drivers/interface/face_auth/**. 94 95**Table 1** describes the HDI APIs for face credential enrollment, authentication, recognition, and deletion. **Table 2** describes the callbacks used to return the executor operation result to the framework or return the authentication tip information to upper-layer applications. 96 97**Table 1** Available APIs 98 99| API | Description | 100| ----------------------------------- | ---------------------------------- | 101| GetExecutorList(std::vector\<sptr\<V1_0::IExecutor>>& executorList) | Obtains the executor list (version V1_0).| 102| GetExecutorListV1_1(std::vector\<sptr\<V1_1::IExecutor>>& executorList) | Obtains the executor list (version V1_1). | 103| GetExecutorInfo(ExecutorInfo& info) | Obtains the executor information, including the executor type, executor role, authentication type, security level, and executor public key.| 104| GetTemplateInfo(uint64_t templateId, TemplateInfo& info) | Obtains information about a face image template based on the specified template ID. | 105| OnRegisterFinish(const std::vector\<uint64_t>& templateIdList,<br> const std::vector\<uint8_t>& frameworkPublicKey, const std::vector\<uint8_t>& extraInfo) | Obtains the public key and template ID list from User_auth after the executor is registered successfully.| 106| Enroll(uint64_t scheduleId, const std::vector\<uint8_t>& extraInfo,<br> const sptr\<IExecutorCallback>& callbackObj) | Enrolls a face image template. | 107| Authenticate(uint64_t scheduleId, const std::vector\<uint64_t>& templateIdList,<br> const std::vector\<uint8_t>& extraInfo, const sptr\<IExecutorCallback>& callbackObj) | Performs facial authentication. | 108| Identify(uint64_t scheduleId, const std::vector\<uint8_t>& extraInfo,<br> const sptr\<IExecutorCallback>& callbackObj) | Performs facial identification. | 109| Delete(const std::vector\<uint64_t>& templateIdList) | Deletes a face image template. | 110| Cancel(uint64_t scheduleId) | Cancels a face enrollment, authentication, or identification operation based on the **scheduleId**. | 111| SendCommand(int32_t commandId, const std::vector\<uint8_t>& extraInfo,<br> const sptr\<IExecutorCallback>& callbackObj) | Sends commands to the Face_auth service. | 112| SetBufferProducer(const sptr\<BufferProducerSequenceable> &bufferProducer) | Sets the preview stream buffer.| 113| GetProperty(const std::vector\<uint64_t>& templateIdList,<br>const std::vector\<GetPropertyType>& propertyTypes, Property& property) | Obtains executor property information.| 114| SetCachedTemplates(const std::vector\<uint64_t> &templateIdList) | Sets a list of templates to be cached.| 115| RegisterSaCommandCallback(const sptr\<ISaCommandCallback> &callbackObj) | Registers a callback to be invoked when an SA command is executed.| 116 117**Table 2** Callbacks 118 119| API | Description | 120| ------------------------------------------------------------ | ------------------------ | 121| IExecutorCallback::OnResult(int32_t code, const std::vector\<uint8_t>& extraInfo) | Called to return the operation result. | 122| IExecutorCallback::OnTip(int32_t code, const std::vector\<uint8_t>& extraInfo) | Called to return the interaction information about the operation process.| 123| ISaCommandCallback::OnSaCommands(const std::vector\<SaCommand>& commands) | Called to send the command list.| 124 125### How to Develop 126 127The following uses the Hi3516D V300 development board as an example to demonstrate how to develop the Face_auth driver. <br/>The directory structure is as follows: 128 129```undefined 130// drivers/peripheral/face_auth 131├── BUILD.gn # Build script 132├── bundle.json # Component description file 133└── hdi_service # Face_auth driver implementation 134 ├── BUILD.gn # Build script 135 ├── include # Header files 136 └── src # Source files 137 ├── executor_impl.cpp # Implementation of authentication and enrollment APIs 138 ├── face_auth_interface_driver.cpp # Face_auth driver entry 139 └── face_auth_interface_service.cpp # Implementation of the APIs for obtaining the executor list 140``` 141 142The development procedure is as follows: 143 1441. Develop the Face_auth driver based on the HDF. The **Bind()**, **Init()**, **Release()**, and **Dispatch()** functions are used. For details about the code, see [face_auth_interface_driver.cpp](https://gitee.com/openharmony/drivers_peripheral/blob/master/face_auth/hdi_service/src/face_auth_interface_driver.cpp). 145 146 ```c++ 147 // Create an IRemoteObject object by using the custom HdfFaceAuthInterfaceHost object, which consists of the IoService object and HDI service. 148 struct HdfFaceAuthInterfaceHost { 149 struct IDeviceIoService ioService; 150 OHOS::sptr<OHOS::IRemoteObject> stub; 151 }; 152 153 // Enable the IPC service to call the response API. 154 static int32_t FaceAuthInterfaceDriverDispatch(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data, 155 struct HdfSBuf *reply) 156 { 157 IAM_LOGI("start"); 158 auto *hdfFaceAuthInterfaceHost = CONTAINER_OF(client->device->service, 159 struct HdfFaceAuthInterfaceHost, ioService); 160 161 OHOS::MessageParcel *dataParcel = nullptr; 162 OHOS::MessageParcel *replyParcel = nullptr; 163 OHOS::MessageOption option; 164 165 if (SbufToParcel(data, &dataParcel) != HDF_SUCCESS) { 166 IAM_LOGE("%{public}s:invalid data sbuf object to dispatch", __func__); 167 return HDF_ERR_INVALID_PARAM; 168 } 169 if (SbufToParcel(reply, &replyParcel) != HDF_SUCCESS) { 170 IAM_LOGE("%{public}s:invalid reply sbuf object to dispatch", __func__); 171 return HDF_ERR_INVALID_PARAM; 172 } 173 174 return hdfFaceAuthInterfaceHost->stub->SendRequest(cmdId, *dataParcel, *replyParcel, option); 175 } 176 177 // Initialize the HdfFaceAuthInterfaceDriver object. 178 int HdfFaceAuthInterfaceDriverInit(struct HdfDeviceObject *deviceObject) 179 { 180 IAM_LOGI("start"); 181 if (!HdfDeviceSetClass(deviceObject, DEVICE_CLASS_USERAUTH)) { 182 IAM_LOGE("set face auth hdf class failed"); 183 return HDF_FAILURE; 184 } 185 return HDF_SUCCESS; 186 } 187 188 // Bind the service provided by the Face_auth driver to the HDF. 189 int HdfFaceAuthInterfaceDriverBind(struct HdfDeviceObject *deviceObject) 190 { 191 IAM_LOGI("start"); 192 auto *hdfFaceAuthInterfaceHost = new (std::nothrow) HdfFaceAuthInterfaceHost; 193 if (hdfFaceAuthInterfaceHost == nullptr) { 194 IAM_LOGE("%{public}s: failed to create HdfFaceAuthInterfaceHost object", __func__); 195 return HDF_FAILURE; 196 } 197 198 hdfFaceAuthInterfaceHost->ioService.Dispatch = FaceAuthInterfaceDriverDispatch; 199 hdfFaceAuthInterfaceHost->ioService.Open = NULL; 200 hdfFaceAuthInterfaceHost->ioService.Release = NULL; 201 202 auto serviceImpl = IFaceAuthInterface::Get(true); 203 if (serviceImpl == nullptr) { 204 IAM_LOGE("%{public}s: failed to implement service", __func__); 205 return HDF_FAILURE; 206 } 207 208 hdfFaceAuthInterfaceHost->stub = OHOS::HDI::ObjectCollector::GetInstance().GetOrNewObject(serviceImpl, 209 IFaceAuthInterface::GetDescriptor()); 210 if (hdfFaceAuthInterfaceHost->stub == nullptr) { 211 IAM_LOGE("%{public}s: Failed to get stub object", __func__); 212 return HDF_FAILURE; 213 } 214 215 deviceObject->service = &hdfFaceAuthInterfaceHost->ioService; 216 IAM_LOGI("success"); 217 return HDF_SUCCESS; 218 } 219 220 // Release resources of the Face_auth driver. 221 void HdfFaceAuthInterfaceDriverRelease(struct HdfDeviceObject *deviceObject) 222 { 223 IAM_LOGI("start"); 224 auto *hdfFaceAuthInterfaceHost = CONTAINER_OF(deviceObject->service, 225 struct HdfFaceAuthInterfaceHost, ioService); 226 delete hdfFaceAuthInterfaceHost; 227 IAM_LOGI("success"); 228 } 229 230 // Register the entry data structure object of the Face_auth driver. 231 struct HdfDriverEntry g_faceAuthInterfaceDriverEntry = { 232 .moduleVersion = 1, 233 .moduleName = "faceauth_interface_service", 234 .Bind = HdfFaceAuthInterfaceDriverBind, 235 .Init = HdfFaceAuthInterfaceDriverInit, 236 .Release = HdfFaceAuthInterfaceDriverRelease, 237 }; 238 239 // Call HDF_INIT to register the driver entry with the HDF. When loading the driver, the HDF calls the Bind() function and then the Init() function. If the Init() function fails to be called, the HDF will call Release() to release driver resources and exit the driver model. 240 HDF_INIT(g_faceAuthInterfaceDriverEntry); 241 ``` 242 2432. Implement the APIs for obtaining the executor list. For details about the code, see [face_auth_interface_service.cpp](https://gitee.com/openharmony/drivers_peripheral/blob/master/face_auth/hdi_service/src/face_auth_interface_service.cpp). 244 245 ```c++ 246 // Executor implementation class 247 class ExecutorImpl : public V1_1::IExecutor { 248 public: 249 ExecutorImpl(struct ExecutorInfo executorInfo); 250 virtual ~ExecutorImpl() {} 251 252 private: 253 struct ExecutorInfo executorInfo_; // Executor information 254 }; 255 256 static constexpr uint16_t SENSOR_ID = 123; // Executor sensor ID 257 static constexpr uint32_t EXECUTOR_TYPE = 123; // Executor type 258 static constexpr size_t PUBLIC_KEY_LEN = 32; //32-byte public key of the executor 259 260 // Create an HDI service object. 261 extern "C" IFaceAuthInterface *FaceAuthInterfaceImplGetInstance(void) 262 { 263 auto faceAuthInterfaceService = new (std::nothrow) FaceAuthInterfaceService(); 264 if (faceAuthInterfaceService == nullptr) { 265 IAM_LOGE("faceAuthInterfaceService is nullptr"); 266 return nullptr; 267 } 268 return faceAuthInterfaceService; 269 } 270 271 // Obtain the executor list and create an executor. 272 int32_t GetExecutorListV1_1(std::vector<sptr<V1_1::IExecutor>>& executorList) 273 { 274 IAM_LOGI("interface mock start"); 275 executorList.clear(); 276 struct ExecutorInfo executorInfoExample = { 277 .sensorId = SENSOR_ID, 278 .executorType = EXECUTOR_TYPE, 279 .executorRole = ExecutorRole::ALL_IN_ONE, 280 .authType = AuthType::FACE, 281 .esl = ExecutorSecureLevel::ESL0, // Executor security level, which ranges from ESL0 to ESL3 (highest). 282 .publicKey = std::vector<uint8_t>(PUBLIC_KEY_LEN, 0), // 32-byte public key, using the Ed25519 algorithm. 283 .extraInfo = {}, 284 }; 285 auto executor = new (std::nothrow) ExecutorImpl(executorInfoExample); 286 if (executor == nullptr) { 287 IAM_LOGE("executor is nullptr"); 288 return HDF_FAILURE; 289 } 290 executorList.push_back(sptr<V1_1::IExecutor>(executor)); 291 IAM_LOGI("interface mock success"); 292 return HDF_SUCCESS; 293 } 294 295 // Obtain the executor list. The method of V1_0 is called to invoke the method of V1_1 through parameter conversion. 296 int32_t GetExecutorList(std::vector<sptr<V1_0::IExecutor>> &executorList) 297 { 298 std::vector<sptr<V1_1::IExecutor>> executorListV1_1; 299 int32_t result = GetExecutorListV1_1(executorListV1_1); 300 for (auto &executor : executorListV1_1) { 301 executorList.push_back(executor); 302 } 303 return result; 304 } 305 ``` 306 3073. Implement each function of the executor. For details about the code, see [executor_impl.cpp](https://gitee.com/openharmony/drivers_peripheral/blob/master/face_auth/hdi_service/src/executor_impl.cpp). 308 309 ```c++ 310 // Obtain the executor information. 311 int32_t GetExecutorInfo(ExecutorInfo& info) 312 { 313 IAM_LOGI("interface mock start"); 314 info = executorInfo_; 315 IAM_LOGI("Executor information got successfully"); 316 return HDF_SUCCESS; 317 } 318 319 // Obtain template information based on templateId. 320 int32_t GetTemplateInfo(uint64_t templateId, TemplateInfo& info) 321 { 322 IAM_LOGI("interface mock start"); 323 static_cast<void>(templateId); 324 info = {0}; 325 IAM_LOGI("Template information got successfully"); 326 return HDF_SUCCESS; 327 } 328 329 // After the executor is successfully registered, obtain the public key and template ID list from User_auth and save the public key. The executor compares its template ID list with the template ID list obtained and updates its template ID list. 330 int32_t OnRegisterFinish(const std::vector<uint64_t>& templateIdList, 331 const std::vector<uint8_t>& frameworkPublicKey, const std::vector<uint8_t>& extraInfo) 332 { 333 IAM_LOGI("interface mock start"); 334 static_cast<void>(templateIdList); 335 static_cast<void>(extraInfo); 336 static_cast<void>(frameworkPublicKey); 337 IAM_LOGI("registration finished"); 338 return HDF_SUCCESS; 339 } 340 341 // Enroll a face image. 342 int32_t Enroll(uint64_t scheduleId, const std::vector<uint8_t>& extraInfo, 343 const sptr<IExecutorCallback>& callbackObj) 344 { 345 IAM_LOGI("interface mock start"); 346 static_cast<void>(scheduleId); 347 static_cast<void>(extraInfo); 348 IAM_LOGI("enroll, result is %{public}d", ResultCode::OPERATION_NOT_SUPPORT); 349 int32_t ret = callbackObj->OnResult(ResultCode::OPERATION_NOT_SUPPORT, {}); 350 if (ret != ResultCode::SUCCESS) { 351 IAM_LOGE("callback result is %{public}d", ret); 352 return HDF_FAILURE; 353 } 354 return HDF_SUCCESS; 355 } 356 357 // Start facial authentication. 358 int32_t Authenticate(uint64_t scheduleId, const std::vector<uint64_t>& templateIdList, 359 const std::vector<uint8_t>& extraInfo, const sptr<IExecutorCallback>& callbackObj) 360 { 361 IAM_LOGI("interface mock start"); 362 static_cast<void>(scheduleId); 363 static_cast<void>(templateIdList); 364 static_cast<void>(extraInfo); 365 IAM_LOGI("authenticate, result is %{public}d", ResultCode::NOT_ENROLLED); 366 int32_t ret = callbackObj->OnResult(ResultCode::NOT_ENROLLED, {}); 367 if (ret != ResultCode::SUCCESS) { 368 IAM_LOGE("callback result is %{public}d", ret); 369 return HDF_FAILURE; 370 } 371 return HDF_SUCCESS; 372 } 373 374 // Perform facial recognition. 375 int32_t Identify(uint64_t scheduleId, const std::vector<uint8_t>& extraInfo, 376 const sptr<IExecutorCallback>& callbackObj) 377 { 378 IAM_LOGI("interface mock start"); 379 static_cast<void>(scheduleId); 380 static_cast<void>(extraInfo); 381 IAM_LOGI("identify, result is %{public}d", ResultCode::OPERATION_NOT_SUPPORT); 382 int32_t ret = callbackObj->OnResult(ResultCode::OPERATION_NOT_SUPPORT, {}); 383 if (ret != ResultCode::SUCCESS) { 384 IAM_LOGE("callback result is %{public}d", ret); 385 return HDF_FAILURE; 386 } 387 return HDF_SUCCESS; 388 } 389 390 // Delete the face image template. 391 int32_t Delete(const std::vector<uint64_t>& templateIdList) 392 { 393 IAM_LOGI("interface mock start"); 394 static_cast<void>(templateIdList); 395 IAM_LOGI("delete success"); 396 return HDF_SUCCESS; 397 } 398 399 // Cancel the operation based on the specified scheduleId. 400 int32_t Cancel(uint64_t scheduleId) 401 { 402 IAM_LOGI("interface mock start"); 403 static_cast<void>(scheduleId); 404 IAM_LOGI("cancel success"); 405 return HDF_SUCCESS; 406 } 407 408 // Send template locking or unlocking command from the Face_auth service to the Face_auth driver. 409 int32_t SendCommand(int32_t commandId, const std::vector<uint8_t>& extraInfo, 410 const sptr<IExecutorCallback>& callbackObj) 411 { 412 IAM_LOGI("interface mock start"); 413 static_cast<void>(extraInfo); 414 int32_t ret; 415 switch (commandId) { 416 case LOCK_TEMPLATE: 417 IAM_LOGI("unlock template, result is %{public}d", ResultCode::SUCCESS); 418 ret = callbackObj->OnResult(ResultCode::SUCCESS, {}); 419 if (ret != ResultCode::SUCCESS) { 420 IAM_LOGE("callback result is %{public}d", ret); 421 return HDF_FAILURE; 422 } 423 break; 424 case UNLOCK_TEMPLATE: 425 IAM_LOGI("unlock template, result is %{public}d", ResultCode::SUCCESS); 426 ret = callbackObj->OnResult(ResultCode::SUCCESS, {}); 427 if (ret != ResultCode::SUCCESS) { 428 IAM_LOGE("callback result is %{public}d", ret); 429 return HDF_FAILURE; 430 } 431 break; 432 default: 433 IAM_LOGD("not support CommandId : %{public}d", commandId); 434 ret = callbackObj->OnResult(ResultCode::GENERAL_ERROR, {}); 435 if (ret != ResultCode::SUCCESS) { 436 IAM_LOGE("callback result is %{public}d", ret); 437 return HDF_FAILURE; 438 } 439 } 440 return HDF_SUCCESS; 441 } 442 443 // Set the preview stream buffer. 444 int32_t ExecutorImpl::SetBufferProducer(const sptr<BufferProducerSequenceable> &bufferProducer) 445 { 446 IAM_LOGI("interface mock start set buffer producer %{public}s", 447 UserIam::Common::GetPointerNullStateString(bufferProducer.GetRefPtr()).c_str()); 448 return HDF_SUCCESS; 449 } 450 451 // Obtaining executor properties. 452 int32_t ExecutorImpl::GetProperty( 453 const std::vector<uint64_t> &templateIdList, const std::vector<GetPropertyType> &propertyTypes, Property &property) 454 { 455 IAM_LOGI("interface mock start"); 456 property = {}; 457 IAM_LOGI("get property success"); 458 return HDF_SUCCESS; 459 } 460 461 // Set a list of templates to be cached. 462 int32_t ExecutorImpl::SetCachedTemplates(const std::vector<uint64_t> &templateIdList) 463 { 464 IAM_LOGI("interface mock start"); 465 IAM_LOGI("set cached templates success"); 466 return HDF_SUCCESS; 467 } 468 469 // Register the callback to be invoked when the SA command is executed. 470 int32_t ExecutorImpl::RegisterSaCommandCallback(const sptr<ISaCommandCallback> &callbackObj) 471 { 472 IAM_LOGI("interface mock start"); 473 IAM_LOGI("register sa command callback success"); 474 return HDF_SUCCESS; 475 } 476 ``` 477 4784. Modify **serviceName2Config** in the **face_auth_service.cpp** file if you need to add a driver or modify driver information. 479 480 ```c++ 481 // base/user_iam/face_auth/services/src/face_auth_service.cpp 482 void FaceAuthService::StartDriverManager() 483 { 484 IAM_LOGI("start"); 485 // Service name and ID of the driver to add or modify. The driver service name and ID must be globally unique. 486 const std::map<std::string, UserAuth::ServiceConfig> serviceName2Config = { 487 {"face_auth_interface_service", {1, std::make_shared<FaceAuthDriverHdi>()}}, 488 }; 489 UserIAM::UserAuth::IDriverManager::GetInstance().Start(serviceName2Config); 490 } 491 ``` 492 493### Verification 494 495Use the [User Authentication APIs](../../application-dev/reference/apis/js-apis-useriam-userauth.md) to develop a JavaScript application and verify the application on the Hi3516D V300 development board. The sample code for verifying and canceling the authentication is as follows: 496 497 ```js 498 // API version 9 499 import userIAM_userAuth from '@ohos.userIAM.userAuth'; 500 501 let challenge = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]); 502 let authType = userIAM_userAuth.UserAuthType.FACE; 503 let authTrustLevel = userIAM_userAuth.AuthTrustLevel.ATL1; 504 505 // Obtain an authentication object. 506 let auth; 507 try { 508 auth = userIAM_userAuth.getAuthInstance(challenge, authType, authTrustLevel); 509 console.log("get auth instance success"); 510 } catch (error) { 511 console.log("get auth instance failed" + error); 512 } 513 514 // Subscribe to the authentication result. 515 try { 516 auth.on("result", { 517 callback: (result: userIAM_userAuth.AuthResultInfo) => { 518 console.log("authV9 result " + result.result); 519 console.log("authV9 token " + result.token); 520 console.log("authV9 remainAttempts " + result.remainAttempts); 521 console.log("authV9 lockoutDuration " + result.lockoutDuration); 522 } 523 }); 524 console.log("subscribe authentication event success"); 525 } catch (error) { 526 console.log("subscribe authentication event failed " + error); 527 } 528 529 // Start user authentication. 530 try { 531 auth.start(); 532 console.info("authV9 start auth success"); 533 } catch (error) { 534 console.info("authV9 start auth failed, error = " + error); 535 } 536 537 // Cancel the authentication. 538 try { 539 auth.cancel(); 540 console.info("Authentication canceled successfully"); 541 } catch (error) { 542 console.info("cancel auth failed, error = " + error); 543 } 544 545 // Unsubscribe from the authentication result. 546 try { 547 auth.off("result"); 548 console.info("cancel subscribe authentication event success"); 549 } catch (error) { 550 console.info("cancel subscribe authentication event failed, error = " + error); 551 } 552 ``` 553