1# User Authentication
2
3## Overview
4
5### Function
6
7User authentication is indispensable in identity authentication scenarios, such as device unlocking, payment, and app logins. The user authentication framework (User_auth) manages the mappings between user identities and authentication credential templates in a unified manner. It schedules executors implemented by basic authentication services (including PIN authentication and facial recognition) to register user authentication credentials, delete credentials, obtain related information, and complete authentication. The figure below shows the architecture of user authentication.
8
9The User_auth driver is developed based on the Hardware Driver Foundation (HDF). It shields hardware differences and provides stable user authentication capabilities for apps and account management system ability (SA). It supports user credential management, authentication information enrollment, authentication scheme generation, and executor information management.
10
11**Figure 1** User authentication architecture
12
13![image](figures/user_auth_architecture.png "User Authentication Architecture")
14
15### Basic Concepts
16The identity authentication consists of the User_auth framework and basic authentication services (including PIN authentication and facial recognition). It supports basic functions such as setting and deleting user credentials and performing authentication.
17
18- Authentication credential information
19
20  An authentication credential template is generated when a user sets a password or enrolls facial information. The credential information consists of the user identity information and credential template information. The authentication is successful when the credential data generated matches the credential template information.
21
22- Authentication credential template
23
24  The authentication credential template is generated and stored by the authentication service when a user sets the authentication credential. 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.
25
26- Executor
27
28  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.
29
30- Executor role
31
32  - ​    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.
33
34  - ​    Collector: only collects data during user authentication. It needs to work with the authenticator to complete user authentication.
35
36  - ​    Authenticator: processes data, obtains the stored credential template, and compares it with the authentication information generated.
37
38- Executor type
39
40  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.
41
42- Executor security level
43
44  Security level of the runtime environment when an executor provides capabilities.
45
46- User_auth public key & executor public key
47
48  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.
49
50    - The executor uses the User_auth public key to verify scheduling instructions. For example, if a face image template is locked, the related facial authentication capability cannot be used. The instruction for unlocking the face image template must be verified before being executed.
51
52    - User_auth uses the executor public key to verify the authentication result accuracy and the integrity of the information exchanged with the executor.
53
54
55- Authentication result trust level
56
57  The trust level of the authentication result varies, depending on the authentication mode and the security level of the authentication execution environment.
58
59- Authentication scheme
60
61  An authentication scheme contains information about the authentication mode, trust level of the authentication result, executor, and credential.
62
63- Scheduling information
64
65  Scheduling information includes the executor information and credential template information required by the executor to process requests. User_auth schedules the executor to implement basic authentication capabilities.
66
67- SA
68
69  SAs are loaded by the System Ability Manager to provide basic system capabilities for OpenHarmony devices.
70
71- Kit
72
73  The kit provides basic APIs for third-party applications.
74
75- Inner API
76
77  Inner API is an API provided by OpenHarmony for system applications.
78
79- IDL interface
80
81  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 User_auth service and driver. For details, see [IDL](https://gitee.com/openharmony/ability_idl_tool/blob/master/README.md).
82
83- IPC
84
85  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).
86
87- HDI
88
89  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 shield underlying hardware device differences for system services. For details, see [HDI Specifications](../../design/hdi-design-specifications.md).
90
91### Working Principles
92
93The User_auth driver shields the differences of security devices and environments. It provides unified interfaces for the User_auth service to implement management of executors and credentials as well as authentication scheme generation.
94You can develop drivers to call Hardware Device Interface (HDI) APIs based on the HDF and the chip you use.
95
96**Figure 2** User_auth service and User_auth driver APIs
97
98![image](figures/user_auth_service_and_driver_api.png "Interaction")
99
100### Constraints
101
102The User_auth driver must be implemented in a TEE to ensure secure storage of user credentials and trustworthiness of user authentication results.
103
104## Development Guidelines
105
106### When to Use
107
108The User_auth driver provides stable user credential management, authentication session management, and executor information management for the User_auth service to ensure successful PIN authentication and biometric recognition on devices.
109
110### Available APIs
111
112The 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/user_auth**.
113**Table 1** describes the HDI APIs for executor registration, credential enrollment and deletion, user authentication, and user identification.
114
115**Table 1** Available APIs
116
117| API      | Description    |
118| --------------------------- | --------------------------- |
119| Init()           | Initializes cached information.                       |
120| AddExecutor(const HdiExecutorRegisterInfo &info, uint64_t &index, std::vector<uint8_t> &publicKey, std::vector<uint64_t> &templateIds) |Adds an executor to obtain the authentication capability.|
121| DeleteExecutor(uint64_t index)            | Deletes an executor.      |
122| OpenSession(int32_t userId, std::vector<uint8_t> &challenge) | Opens a session for authentication credential management.     |
123| CloseSession(int32_t userId)        | Closes a session for authentication credential management.           |
124| BeginEnrollment(const std::vector<uint8_t> &authToken, const HdiEnrollParam &param, HdiScheduleInfo &info) | Enrolls the user authentication credential. If a user has enrolled a PIN, the old PIN will be overwritten. |
125| UpdateEnrollmentResult(int32_t userId, const std::vector<uint8_t> & scheduleResult, EnrollResultInfo &info)| Updates the data to complete this enrollment.  |
126| CancelEnrollment(int32_t userId)     | Cancels an enrollment.         |
127| DeleteCredential(int32_t userId, uint64_t credentialId, const std::vector<uint8_t> &authToken, CredentialInfo &info) | Deletes credential information based on the specified **credentialId**.                              |
128| DeleteUser(int32_t userId, const std::vector<uint8_t> &authToken, std::vector<CredentialInfo> &deletedInfos, std::vector<uint8_t> &rootSecret) | Deletes a user PIN from User_auth.                       |
129| EnforceDeleteUser(int32_t userId, std::vector<CredentialInfo> &deletedInfos) | Forcibly deletes a user. This API will be called when a user is deleted from the system.              |
130| GetCredential(int32_t userId, int32_t authType, std::vector<CredentialInfo> &infos) | Obtains user credential information by authentication type.            |
131| BeginAuthentication(uint64_t contextId, const HdiAuthParam &param, std::vector<HdiScheduleInfo> &infos) | Starts an authentication to generate the authentication scheme and scheduling information.                          |
132| UpdateAuthenticationResult(uint64_t contextId, const std::vector<uint8_t> & scheduleResult, HdiAuthResultInfo &info, HdiEnrolledState &enrolledState)| Updates the authentication result to evaluate the authentication scheme.                  |
133| CancelAuthentication(uint64_t contextId)      | Cancels an authentication.            |
134| BeginIdentification(uint64_t contextId, int32_t authType, const std::vector<uint8_t> &challenge, uint32_t executorSensorHint, HdiScheduleInfo &scheduleInfo) | Starts an identification to generate the identification scheme and scheduling information.                          |
135| UpdateIdentificationResult(uint64_t contextId, const std::vector<uint8_t> &scheduleResult, IdentifyResultInfo &info) | Updates the identification result to evaluate the identification scheme.                  |
136| CancelIdentification(uint64_t contextId)             | Cancels an identification.             |
137| GetAuthTrustLevel(int32_t userId, int32_t authType, uint32_t &authTrustLevel) | Obtains the authentication trust level of the specified authentication type.    |
138| GetValidSolution(int32_t userId, const std::vector<int32_t> &authTypes, uint32_t authTrustLevel, std::vector<int32_t> &validTypes) | Obtains the valid authentication scheme based on the authentication trust level for a user.                  |
139| GetAllUserInfo(std::vector<UserInfo> &userInfos) | Obtains all user information (excluding **userId**). |
140| GetUserInfo(int32_t userId, uint64_t &secureUid, int32_t &pinSubType, std::vector<EnrolledInfo> &infos) | Obtains user information. |
141| GetAllExtUserInfo(std::vector<ExtUserInfo> &userInfos) | Obtains all user information (including **userId**). |
142| GetEnrolledState(int32_t userId, int32_t authType, HdiEnrolledState &enrolledState) | Obtains enrollment information. |
143| CheckReuseUnlockResult(const ReuseUnlockParam& param, ReuseUnlockInfo& info) | Checks whether the device unlocking result is reused. |
144| SendMessage(uint64_t scheduleId, int32_t srcRole, const std::vector<uint8_t>& msg) | Sends messages to the executor. |
145| RegisterMessageCallback(const sptr<IMessageCallback>& messageCallback) | Registers a callback for executor messages.|
146| GetLocalScheduleFromMessage(const std::vector<uint8_t>& remoteDeviceId, const std::vector<uint8_t>& message, HdiScheduleInfo& scheduleInfo) | Obtains scheduling information of the local executor. |
147| GetSignedExecutorInfo(const std::vector<int32_t>& authTypes, int32_t executorRole, const std::vector<uint8_t>& remoteDeviceId, std::vector<uint8_t>& signedExecutorInfo) | Obtains information about the signed executor. |
148
149### How to Develop
150
151The following uses the Hi3516D V300 development board as an example to demonstrate how to develop the User_auth driver. <br/>The directory structure is as follows:
152
153```undefined
154// drivers/peripheral/user_auth
155├── BUILD.gn     # Build script
156├── bundle.json # Component description file
157└── hdi_service # User_auth driver implementation
158    ├── BUILD.gn     # Build script
159    ├── module # Implementation of functionalities
160    └── service
161        ├── user_auth_interface_driver.cpp # User_auth driver entry
162        └── user_auth_interface_service.cpp # Implementation of the APIs for obtaining the executor list
163```
164
165The development procedure is as follows:
166
1671. Develop the User_auth driver based on the HDF. The **Bind()**, **Init()**, **Release()**, and **Dispatch()** functions are used. For details about the code, see [user_auth_interface_driver.cpp](https://gitee.com/openharmony/drivers_peripheral/blob/master/user_auth/hdi_service/service/user_auth_interface_driver.cpp).
168
169   ```c++
170   // Create an IRemoteObject object by using the custom HdfUserAuthInterfaceHost object, which consists of the IoService object and HDI service.
171   struct HdfUserAuthInterfaceHost {
172       struct IDeviceIoService ioService;
173       OHOS::sptr<OHOS::IRemoteObject> stub;
174   };
175
176   // Enable the IPC service to call the response API.
177   static int32_t UserAuthInterfaceDriverDispatch(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data,
178       struct HdfSBuf *reply)
179   {
180       auto *hdfUserAuthInterfaceHost = CONTAINER_OF(client->device->service, struct HdfUserAuthInterfaceHost, ioService);
181
182       OHOS::MessageParcel *dataParcel = nullptr;
183       OHOS::MessageParcel *replyParcel = nullptr;
184       OHOS::MessageOption option;
185
186       if (SbufToParcel(data, &dataParcel) != HDF_SUCCESS) {
187           HDF_LOGE("%{public}s:invalid data sbuf object to dispatch", __func__);
188           return HDF_ERR_INVALID_PARAM;
189       }
190       if (SbufToParcel(reply, &replyParcel) != HDF_SUCCESS) {
191           HDF_LOGE("%{public}s:invalid reply sbuf object to dispatch", __func__);
192           return HDF_ERR_INVALID_PARAM;
193       }
194
195       return hdfUserAuthInterfaceHost->stub->SendRequest(cmdId, *dataParcel, *replyParcel, option);
196   }
197
198   // Initialize the HdfUserAuthInterfaceDriver object.
199   int HdfUserAuthInterfaceDriverInit(struct HdfDeviceObject *deviceObject)
200   {
201       HDF_LOGI("HdfUserAuthInterfaceDriverInit enter");
202       OHOS::UserIAM::Common::Init();
203       return HDF_SUCCESS;
204   }
205
206   // Bind the service provided by the User_auth driver to the HDF.
207   int HdfUserAuthInterfaceDriverBind(struct HdfDeviceObject *deviceObject)
208   {
209       HDF_LOGI("HdfUserAuthInterfaceDriverBind enter");
210
211       auto *hdfUserAuthInterfaceHost = new (std::nothrow) HdfUserAuthInterfaceHost;
212       if (hdfUserAuthInterfaceHost == nullptr) {
213           HDF_LOGE("%{public}s: failed to create HdfUserAuthInterfaceHost object", __func__);
214           return HDF_FAILURE;
215       }
216
217       hdfUserAuthInterfaceHost->ioService.Dispatch = UserAuthInterfaceDriverDispatch;
218       hdfUserAuthInterfaceHost->ioService.Open = NULL;
219       hdfUserAuthInterfaceHost->ioService.Release = NULL;
220
221       auto serviceImpl = IUserAuthInterface::Get(true);
222       if (serviceImpl == nullptr) {
223           HDF_LOGE("%{public}s: failed to implement service", __func__);
224           return HDF_FAILURE;
225       }
226
227       hdfUserAuthInterfaceHost->stub = OHOS::HDI::ObjectCollector::GetInstance().GetOrNewObject(serviceImpl,
228           IUserAuthInterface::GetDescriptor());
229       if (hdfUserAuthInterfaceHost->stub == nullptr) {
230           HDF_LOGE("%{public}s: failed to get stub object", __func__);
231           return HDF_FAILURE;
232       }
233
234       deviceObject->service = &hdfUserAuthInterfaceHost->ioService;
235       return HDF_SUCCESS;
236   }
237
238   // Release resources of the User_auth driver.
239   void HdfUserAuthInterfaceDriverRelease(struct HdfDeviceObject *deviceObject){
240       HDF_LOGI("HdfUserAuthInterfaceDriverRelease enter");
241       auto *hdfUserAuthInterfaceHost = CONTAINER_OF(deviceObject->service, struct HdfUserAuthInterfaceHost, ioService);
242       delete hdfUserAuthInterfaceHost;
243   }
244
245   // Register the User_auth driver entry data structure object.
246   struct HdfDriverEntry g_userAuthInterfaceDriverEntry = {
247       .moduleVersion = 1,
248       .moduleName = "user_auth_device_driver",
249       .Bind = HdfUserAuthInterfaceDriverBind,
250       .Init = HdfUserAuthInterfaceDriverInit,
251       .Release = HdfUserAuthInterfaceDriverRelease,
252   };
253
254   // 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.
255   #ifndef __cplusplus
256   extern "C" {
257   #endif
258   HDF_INIT(g_userAuthInterfaceDriverEntry);
259   #ifndef __cplusplus
260   }
261   #endif
262   ```
263
2642. Register the executor. For details about the code, see [user_auth_interface_service.cpp](https://gitee.com/openharmony/drivers_peripheral/blob/master/user_auth/hdi_service/service/user_auth_interface_service.cpp).
265
266   ```c++
267   // Add an executor.
268   int32_t UserAuthInterfaceService::AddExecutor(const HdiExecutorRegisterInfo &info, uint64_t &index,
269    std::vector<uint8_t> &publicKey, std::vector<uint64_t> &templateIds)
270   {
271       GlobalLock();
272       ExecutorInfoHal executorInfoHal;
273       CopyExecutorInfo(info, executorInfoHal);
274       int32_t ret = RegisterExecutor(&executorInfoHal, &index);
275       GlobalUnLock();
276       return ret;
277   }
278
279   // Delete the executor.
280   int32_t UserAuthInterfaceService::DeleteExecutor(uint64_t index)
281   {
282       return UnRegisterExecutor(index);
283   }
284   ```
285
2863. Enroll user authentication data. For details about the code, see [user_auth_interface_service.cpp](https://gitee.com/openharmony/drivers_peripheral/blob/master/user_auth/hdi_service/service/user_auth_interface_service.cpp).
287
288   ```c++
289   // Open a session for authentication credential management.
290   int32_t UserAuthInterfaceService::OpenSession(int32_t userId, std::vector<uint8_t>& challenge)
291   {
292       GlobalLock();
293       uint64_t challengeU64 = 0;
294       int32_t ret = OpenEditSession(userId, &challengeU64);
295       challenge.resize(sizeof(uint64_t));
296       if (memcpy_s(&challenge[0], challenge.size(), &challengeU64, sizeof(uint64_t)) != EOK) {
297           IAM_LOGE("failed to copy challengeU64");
298           return RESULT_BAD_COPY;
299       }
300       GlobalUnLock();
301       return ret;
302   }
303
304   // Close the session for authentication credential management.
305   int32_t UserAuthInterfaceService::CloseSession(int32_t userId)
306   {
307       GlobalLock();
308       int32_t ret = CloseEditSession();
309       GlobalUnLock();
310       return ret;
311   }
312
313   // Start enrollment to generate enrollment and scheduling information.
314   int32_t UserAuthInterfaceService::BeginEnrollment(
315    const std::vector<uint8_t> &authToken, const HdiEnrollParam &param, HdiScheduleInfo &info)
316   {
317       IAM_LOGI("start");
318       GlobalLock();
319       if (authToken.size() != sizeof(UserAuthTokenHal) && param.authType != PIN) {
320           IAM_LOGE("authToken len is invalid");
321           GlobalUnLock();
322           return RESULT_BAD_PARAM;
323       }
324       PermissionCheckParam checkParam;
325       if (authToken.size() == sizeof(UserAuthTokenHal) &&
326           memcpy_s(checkParam.token, AUTH_TOKEN_LEN, &authToken[0], authToken.size()) != EOK) {
327           GlobalUnLock();
328           return RESULT_BAD_COPY;
329       }
330       checkParam.authType = param.authType;
331       checkParam.userId = userId;
332       checkParam.authSubType = (uint64_t)param.executorType;
333       CoAuthSchedule scheduleInfo;
334       int32_t ret = CheckEnrollPermission(checkParam, &scheduleInfo.scheduleId);
335       if (ret != RESULT_SUCCESS) {
336           IAM_LOGE("Failed to check permission");
337           GlobalUnLock();
338           return ret;
339       }
340       ret = GetCoAuthSchedule(&scheduleInfo);
341       if (ret != RESULT_SUCCESS) {
342           IAM_LOGE("Failed to get schedule info");
343           GlobalUnLock();
344           return ret;
345       }
346       if (!CopyScheduleInfo(&scheduleInfo, &info)) {
347           IAM_LOGE("Failed to copy schedule info");
348           ret = RESULT_BAD_COPY;
349       }
350       GlobalUnLock();
351       return ret;
352   }
353
354   // Cancel the enrollment.
355   int32_t UserAuthInterfaceService::CancelEnrollment(int32_t userId)
356   {
357       IAM_LOGI("start");
358       BreakOffCoauthSchedule(userId);
359       return RESULT_SUCCESS;
360   }
361
362   // Update the enrolled credential information.
363   int32_t UserAuthInterfaceService::UpdateEnrollmentResult(int32_t userId, const std::vector<uint8_t> &scheduleResult, EnrollResultInfo &info)
364   {
365       IAM_LOGI("start");
366       GlobalLock();
367       if (scheduleResult.size() == 0) {
368           IAM_LOGE("enrollToken is invalid");
369           GlobalUnLock();
370           return RESULT_BAD_PARAM;
371       }
372       Buffer *scheduleResultBuffer = CreateBufferByData(&scheduleResult[0], scheduleResult.size());
373       if (scheduleResultBuffer == nullptr) {
374           IAM_LOGE("scheduleTokenBuffer is null");
375           GlobalUnLock();
376           return RESULT_NO_MEMORY;
377       }
378       bool isUpdate;
379       int32_t ret = GetIsUpdate(&isUpdate);
380       if (ret != RESULT_SUCCESS) {
381           IAM_LOGE("Failed to get isUpdate");
382           return ret;
383       }
384       if (isUpdate) {
385           CredentialInfoHal oldCredentialHal;
386           ret = UpdateCredentialFunc(scheduleResultBuffer, &credentialId, &oldCredentialHal);
387           oldInfo.authType = static_cast<AuthType>(oldCredentialHal.authType);
388           oldInfo.credentialId = oldCredentialHal.credentialId;
389           oldInfo.templateId = oldCredentialHal.templateId;
390           oldInfo.executorType = static_cast<uint32_t>(oldCredentialHal.authSubType);
391           oldInfo.executorId = 0;
392           oldInfo.index = 0;
393       } else {
394           ret = AddCredentialFunc(scheduleResultBuffer, &credentialId);
395       }
396       DestoryBuffer(scheduleResultBuffer);
397       GlobalUnLock();
398       return ret;
399   }
400   ```
401
4024. Perform the authentication. For details about the code, see [user_auth_interface_service.cpp](https://gitee.com/openharmony/drivers_peripheral/blob/master/user_auth/hdi_service/service/user_auth_interface_service.cpp).
403
404   ```c++
405   // Create an HDI service object.
406   extern "C" IUserAuthInterface *UserAuthInterfaceImplGetInstance(void)
407   {
408       auto userAuthInterfaceService = new (std::nothrow) UserAuthInterfaceService();
409       if (userAuthInterfaceService == nullptr) {
410           IAM_LOGE("userAuthInterfaceService is nullptr");
411           return nullptr;
412       }
413       return userAuthInterfaceService;
414   }
415
416   // Start an authentication to generate the authentication scheme and scheduling information.
417   int32_t UserAuthInterfaceService::BeginAuthentication(uint64_t contextId, const HdiAuthParam &param,
418    std::vector<HdiScheduleInfo> &infos)
419   {
420       IAM_LOGI("start");
421       if (param.challenge.size() != sizeof(uint64_t)) {
422           IAM_LOGE("Failed to copy challenge");
423           return RESULT_BAD_PARAM;
424       }
425       GlobalLock();
426       CoAuthSchedule *schedulesGet = nullptr;
427       uint32_t scheduleIdNum = 0;
428       AuthSolutionHal solutionIn;
429       solutionIn.contextId = contextId;
430       solutionIn.userId = param.userId;
431       solutionIn.authType = static_cast<uint32_t>(param.authType);
432       solutionIn.authTrustLevel = param.authTrustLevel;
433       if (memcpy_s(&solutionIn.challenge, sizeof(uint64_t), &param.challenge[0],
434           param.challenge.size()) != EOK) {
435           IAM_LOGE("Failed to copy challenge");
436           GlobalUnLock();
437           return RESULT_BAD_COPY;
438       }
439       int32_t ret = GenerateSolutionFunc(solutionIn, &schedulesGet, &scheduleIdNum);
440       if (ret != RESULT_SUCCESS) {
441           IAM_LOGE("Failed to generate solution");
442           GlobalUnLock();
443           return ret;
444       }
445       for (uint32_t i = 0; i < scheduleIdNum; i++) {
446           ScheduleInfoV1_1 temp;
447           if (!CopyScheduleInfo(schedulesGet + i, &temp)) {
448               infos.clear();
449               ret = RESULT_GENERAL_ERROR;
450               break;
451           }
452           infos.push_back(temp);
453       }
454       free(schedulesGet);
455       GlobalUnLock();
456       return ret;
457   }
458
459   // Update the authentication result to evaluate the authentication scheme.
460   int32_t UserAuthInterfaceService::UpdateAuthenticationResult(uint64_t contextId,
461    const std::vector<uint8_t> &scheduleResult, HdiAuthResultInfo &info, HdiEnrolledState &enrolledState)
462   {
463       IAM_LOGI("start");
464       GlobalLock();
465       if (scheduleResult.size() == 0) {
466           IAM_LOGE("param is invalid");
467           info.result = RESULT_BAD_PARAM;
468           GlobalUnLock();
469           return RESULT_BAD_PARAM;
470       }
471       Buffer *scheduleResultBuffer = CreateBufferByData(&scheduleResult[0], scheduleResult.size());
472       if (scheduleResultBuffer == nullptr) {
473           IAM_LOGE("scheduleTokenBuffer is null");
474           info.result = RESULT_GENERAL_ERROR;
475           GlobalUnLock();
476           return RESULT_NO_MEMORY;
477       }
478       UserAuthTokenHal authTokenHal;
479       info.result = RequestAuthResultFunc(contextId, scheduleResultBuffer, &authTokenHal);
480       if (info.result != RESULT_SUCCESS) {
481           IAM_LOGE("Failed to execute func");
482           DestoryBuffer(scheduleResultBuffer);
483           GlobalUnLock();
484           return info.result;
485       }
486       info.token.resize(sizeof(UserAuthTokenHal));
487       if (memcpy_s(&info.token[0], info.token.size(), &authTokenHal, sizeof(authTokenHal)) != EOK) {
488           IAM_LOGE("Failed to copy authToken");
489           DestoryBuffer(scheduleResultBuffer);
490           GlobalUnLock();
491           return RESULT_BAD_COPY;
492       }
493       DestoryBuffer(scheduleResultBuffer);
494       GlobalUnLock();
495       return RESULT_SUCCESS;
496   }
497
498   // Cancel the authentication.
499   int32_t UserAuthInterfaceService::CancelAuthentication(uint64_t contextId)
500   {
501       IAM_LOGI("start");
502       GlobalLock();
503       uint32_t scheduleIdNum = 0;
504       int32_t ret = CancelContextFunc(contextId, nullptr, &scheduleIdNum);
505       if (ret != RESULT_SUCCESS) {
506           IAM_LOGE("Failed to execute func");
507           GlobalUnLock();
508           return ret;
509       }
510       GlobalUnLock();
511       return RESULT_SUCCESS;
512   }
513   ```
514
515### Verification
516
517Use the [User Authentication APIs](../../application-dev/reference/apis-user-authentication-kit/js-apis-useriam-userauth.md) to develop a HAP and verify the application on the RK3568 platform.
518
5191. Initiate a request for user authentication and obtain the authentication result.
520
521```ts
522  // API version 10
523  import type {BusinessError} from '@ohos.base';
524  import userIAM_userAuth from '@ohos.userIAM.userAuth';
525
526  // Set authentication parameters.
527  const authParam: userIAM_userAuth.AuthParam = {
528    challenge: new Uint8Array([49, 49, 49, 49, 49, 49]),
529    authType: [userIAM_userAuth.UserAuthType.PIN, userIAM_userAuth.UserAuthType.FACE],
530    authTrustLevel: userIAM_userAuth.AuthTrustLevel.ATL3,
531  };
532  // Set the authentication page.
533  const widgetParam: userIAM_userAuth.WidgetParam = {
534    title: 'Verify identity',
535  };
536  try {
537    // Obtain an authentication object.
538    let userAuthInstance = userIAM_userAuth.getUserAuthInstance(authParam, widgetParam);
539    console.info('get userAuth instance success');
540    // Subscribe to the authentication result.
541    userAuthInstance.on('result', {
542      onResult(result) {
543        console.info(`userAuthInstance callback result: ${JSON.stringify(result)}`);
544        // Unsubscribe from the authentication result if required.
545        userAuthInstance.off('result');
546      }
547  });
548    console.info('auth on success');
549    userAuthInstance.start();
550    console.info('auth start success');
551  } catch (error) {
552    const err: BusinessError = error as BusinessError;
553    console.error(`auth catch error. Code is ${err?.code}, message is ${err?.message}`);
554  }
555```
556
5572. Cancel an authentication.
558
559```ts
560  // API version 10
561  import type {BusinessError} from '@ohos.base';
562  import userIAM_userAuth from '@ohos.userIAM.userAuth';
563
564  const authParam: userIAM_userAuth.AuthParam = {
565    challenge: new Uint8Array([49, 49, 49, 49, 49, 49]),
566    authType: [userIAM_userAuth.UserAuthType.PIN, userIAM_userAuth.UserAuthType.FACE],
567    authTrustLevel: userIAM_userAuth.AuthTrustLevel.ATL3,
568  };
569  const widgetParam: userIAM_userAuth.WidgetParam = {
570    title: 'Verify identity',
571  };
572  try {
573    // Obtain an authentication object.
574    let userAuthInstance = userIAM_userAuth.getUserAuthInstance(authParam, widgetParam);
575    console.info('get userAuth instance success');
576    // Start user authentication.
577    userAuthInstance.start();
578    console.info('auth start success');
579    // Cancel the authentication.
580    userAuthInstance.cancel();
581    console.info('auth cancel success');
582  } catch (error) {
583    const err: BusinessError = error as BusinessError;
584    console.error(`auth catch error. Code is ${err?.code}, message is ${err?.message}`);
585  }
586```
587