LOGIN WITH “iAM Smart”
Table of Contents
1. Introduction
This is a general walk-through for getting start iAM Smart APIs development of Login with “iAM Smart” use case.
Developers of Online Service adopting iAM Smart may find this guide useful when designing and developing application flows for login with “iAM Smart” adopting iAM Smart functions.
In this guide we will provide guides on:
- Setting up your iAM Smart development environment
- Authentication
- User link-up First Time Log in
- User Registration
- Request QR Page
- Callback with authCode to Online Service Server
- Request accessToken & Tokenised ID
2. User Journey

3. Flow
Please find below the sequence diagram for the whole re-authentication:

4. Authentication
4.1 User Journey

4.2 Click login by “iAM Smart”
Online service shall display the following buttons:
Login with iAM Smart | |
Usage | The button for user to initiate the authentication flow. |
Traditional Chinese | 智方便登入 |
Simplified Chinese | 智方便登入 |
English | Login with iAM Smart |
Sample Button for Login with iAM Smart | |
Traditional Chinese | ![]() |
Simplified Chinese | ![]() |
English | ![]() |
Online services is required to add a link / button, “More info” or “了解更多” in the initiation page. The link / button shall be linked to the “iAM Smart” thematic webpage based on language preference of user. The initiation page refers to the page that initiates the “iAM Smart” service, which user clicks the “iAM Smart” button to initiate the interaction with “iAM Smart” mobile application.
Language | Link |
English | https://www.iamsmart.gov.hk/en/ |
Traditional Chinese | https://www.iamsmart.gov.hk/tc/ |
Simplified Chinese | https://www.iamsmart.gov.hk/sc/ |
4.3 Request QR Page
In this step, a user initiates for using iAM Smart at online service application. Online service redirects the user to a webpage hosted by iAM Smart System. Broker page will be shown on the webpage.
Composing Request URL
Parameter | Type | Presence | Description |
clientID | String | Required | Online Service client identifier. The clientID will be assigned to Online Service at the initial registration |
responseType | String | Required | value MUST be set to code |
source | String | Required | Request initiator. The supported source values can be found in Appendix B of this specification. |
redirectURI | String | Required | callback redirect URI. The value should be URL encoded |
scope | String | Required | specify the scope of iAM Smart functions (eidapi_auth, eidapi_formFilling, eidapi_sign or eidapi_fr) to be requested. The list of scopes and how to request for multiple scopes are described in Section 5.3. The value should be URL encoded. |
ticketID | String | Required (Conditional) | Required only in anonymous form filling or anonymous signing workflows for getting QR page. |
lang | String | Optional | Language to display: en-US, zh-HK, or zh-CN. If this parameter is not specified, zh-HK will be shown. |
state | String | Optional | If state parameter is presented in the request message, the same state value will be returned to Online Service during callback. It is used to prevent the CSRF attack. The value of state is defined by Online Service and it should be a secure random string of any length less than or equal to 36 (UUID string length). Only ASCII letters, numbers, underscore and hyphen are accepted. |
brokerPage | Boolean | Optional | If brokerPage is set to true, Universal Link (iOS) / App Link (Android) will be leveraged to open iAM Smart Mobile App. This feature is useful for Online Service supporting mobile web version while trigger iAM Smart Mobile App or showing QR page automatically. (i.e. Show QR page without detecting whether iAM Smart Mobile App is installed). The default value is false. |
Your request URL should look something like this:
Get
https:///api/v1/auth/getQR
?clientID=Online Service1
&responseType=code
&source=Android_Chrome
&redirectURI=https%3A%2F%2Frp_domain%2Frp_context%2Fcall_back_endpoint
&scope=eidapi_auth%20eidapi_formFlling
&lang=en-US
&state=eb9b7b8eddd5
If the brokerPage is set to be true, then the following page will be displayed.

Otherwise, the QR page will be displayed, and client need to use “iAM Smart” app to scan the QR code for authorisation.

4.4 Callback with authCode to Online Service Server
After user confirming the authorisation, “iAM Smart” core system will redirect to Online Service callback URL with authCode.
4.4.1 Callback Parameters
Parameter | Type | Presence | Description |
businessID | String | Required (Conditional) | businessID will only be returned in anonymous workflows. businessID is a unique identifier for Online Service to differentiate different request. Online Service can use the businessID to relate the callback message with the original request. |
code | String | Required (Conditional) | The authorisation code generated by the iAM Smart System. The authorisation code will be expired in 1 minute after issued. Online Service MUST NOT use the authorisation code more than once. An error message will be returned if an authorisation code is expired or re-used. |
state | String | Optional | If the state parameter has been presented in the request, the same state value will be returned during callback. It is used to prevent the CSRF attack. The value of state is defined by Online Service and it should be a secure random value. |
error_code | String | Requried (Conditional) | Return error code when exception. |
The callback should look something like this:
GET
https://
?code=0ad186353c424c64897fcc00445c9ba1
&state=eddd527b6
4.5 Request accessToken & Tokenised ID
After obtaining the authCode from “iAM Smart” core system, Online Service can request accessToken and Tokenised ID from “iAM Smart” core system with authCode.
4.5.1 Composing Request Body
Parameter | Type | Presence | Description |
businessID | String | Required | businessID is a unique identifier for Online Service to differentiate different request, Online Service can use the businessID to relate the callback message with the original request. |
state | String | Optional | If state parameter is present in the request message, the same state value will be returned. It is used to prevent the CSRF attack. The value of state is defined by Online Service and it should be a secure random value. |
isPassed | String | Required | Re-authentication result. true – same person, otherwise false. |
Upon success you should receive the encrypted response:
POST
https:///api/v1/auth/getToken
// Request Headers
clientID: "edae2e2529ff46228af1e4d18c8405d1"
signatureMethod: "HmacSHA256"
signature: "5X42Y1B7MEd8Mm%2BonwjiQz9VCZkkrntADskXsYntavU%3D"
timestamp: 1557048906183
nonce: "e893647dc4204eb9b7b8eddd527b687c"
// Request Body
{
"code": "xxxa42e76bf4cb0846a68e6d83d6096",
"grantType": "authorization_code"
}
Encryption
To better protect the data in transit, an additional layer of data encryption will be applied to all APIs POST request (except the one that Online Service request for getting symmetric encryption key)
Info |
To encrypt the data, a Content Encryption Key is required, please refer to iAM Smart API Specification 6.3.1.1 or online mockup API. |
In this case we will use a mock-up Content Encryption Key (CEK), please find below a base64-encoded mock CEK:
pvD2Zc1mf7tKVh17JOftmzyTaDyVmcULg92nB9qeEoQ=
You may refer to the pseudo code below for the encryption implementation:
private static final String AES_GCM_NOPADDING = "AES/GCM/NoPadding";
/**
* AES GCM encryption
* @param contentByte - Bytes of content to be encrypted
* @param key - CEK (AES 256)
* @return
*/
public static String encrypt(byte[] contentByte, byte[] key) {
SecretKeySpec skeySpec = new SecretKeySpec(key, AES);
byte[] encrypted = null;
try {
SecureRandom secureRandom = new SecureRandom();
byte[] iv = new byte[12];
// do not reuse iv with the same key
secureRandom.nextBytes(iv);
Cipher cipher = Cipher.getInstance(AES_GCM_NOPADDING);
GCMParameterSpec parameterSpec = new GCMParameterSpec(128, iv);
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, parameterSpec);
encrypted = cipher.doFinal(contentByte);
ByteBuffer byteBuffer = ByteBuffer.allocate(
4 + iv.length + encrypted.length);
byteBuffer.putInt(iv.length);
byteBuffer.put(iv);
byteBuffer.put(encrypted);
byte[] cipherMessage = byteBuffer.array();
return Base64Util.base64Encode(cipherMessage);
} catch (NoSuchAlgorithmException | NoSuchPaddingException
| InvalidKeyException | InvalidAlgorithmParameterException
| IllegalBlockSizeException | BadPaddingException e) {
log.error("Encryption error: {}", e);
throw new IAMSmartException(e);
}
}
Note |
Please note that the pseudo code ONLY aims for reference and shall provide NO SUPPORT for any issue on the pseudo code. |
Please find below an example of base64-encoded IV:
vM7EArooK0hCCX8E
If you use the above json and encrypt with the above CEK and IV, concatenated and base64 encoded, you should get the following result:
AAAADLzOxAK6KCtIQgl/BJRVECazUaNiaf13rfcGNApA3K0BI0qZkB5pMWAjcTF0z0PLOnsCyxCtVUytAbA/cm2U5W83FrRXvtZZ74SrCWY4cQiAlq38TLSeOY9B418Tc5dUr1JnbCVeHe8HNrEY81QyI3r7JMZfXGaWgRoz0os8C7zbzty88vPGPSmBE7WqZF5I84IJ7wzwpRs+ifz9DfpFqWzj55mftTHQERWDhcKRALgdZECoFCqtmNhRFERxAm+MrIkypZG/JAdcho0cLyIGTkw7KLqKT0/NmQgQ3vsi6IxGOF4u8gPfLHfRkLopZkU7sXXHNC5hVtEmGXz0zrp+Pq9diKIX6MyrAtwjhIxxKu5iI9MO7XB272hpeonpJYWA0dvh0F882tjNnN6oRJrQ1ZxPXfeA
Now put it in the value of JSON name/value pair called “content” as the request body:
{"content": "AAAADLzOxAK6KCtIQgl/BJRVECazUaNiaf13rfcGNApA3K0BI0qZkB5pMWAjcTF0z0PLOnsCyxCtVUytAbA/cm2U5W83FrRXvtZZ74SrCWY4cQiAlq38TLSeOY9B418Tc5dUr1JnbCVeHe8HNrEY81QyI3r7JMZfXGaWgRoz0os8C7zbzty88vPGPSmBE7WqZF5I84IJ7wzwpRs+ifz9DfpFqWzj55mftTHQERWDhcKRALgdZECoFCqtmNhRFERxAm+MrIkypZG/JAdcho0cLyIGTkw7KLqKT0/NmQgQ3vsi6IxGOF4u8gPfLHfRkLopZkU7sXXHNC5hVtEmGXz0zrp+Pq9diKIX6MyrAtwjhIxxKu5iI9MO7XB272hpeonpJYWA0dvh0F882tjNnN6oRJrQ1ZxPXfeA" }
4.5.2 Composing Common Request Header
Parameter | Type | Presence | Description |
clientID | String | Required | Online Service client identifier. The clientID will be assigned to online service at the initial registration |
signatureMethod | String | Required | signature algorithm: HmacSHA256 |
timestamp | Long | Required | The timestamp is the request submit time expressed in the number of milliseconds since January 1, 1970 00:00:00 GMT. It is used to prevent replay attack. The value MUST be a positive integer and equal or greater than the timestamp used in previous requests. |
nonce | String | Required | A nonce is a random string, uniquely generated for each request by online service. It is used to prevent replay attack. A nonce can be an ASCII string of any length less than or equal to 36 (UUID string length) as long as the uniqueness requirement is met. |
signature | String | Required | It is a signature of the submitted data. Online service uses clientSecret to sign the concatenated string of clientID, signatureMethod, timestamp, nonce, and request body to get the signature. The pseudo code to generate the signature is shown at below. |
Online Service uses clientSecret to sign the concatenated string of ClientID, signatureMethod, timestamp, nonce and request body to get the signature.
In this case, we will use the following parameters for signature generation:
clientID: clientID20220817demo
clientSecret: clientSecret20220817demo
signatureMethod: HmacSHA256
timestamp: 1660721425291
nonce: nonce20220817
The concatenated string of ClientID, signatureMethod, timestamp, nonce and request body should be as follow:
clientID20220817demoHmacSHA2561660721425291nonce20220817{"content": "AAAADLzOxAK6KCtIQgl/BJRVECazUaNiaf13rfcGNApA3K0BI0qZkB5pMWAjcTF0z0PLOnsCyxCtVUytAbA/cm2U5W83FrRXvtZZ74SrCWY4cQiAlq38TLSeOY9B418Tc5dUr1JnbCVeHe8HNrEY81QyI3r7JMZfXGaWgRoz0os8C7zbzty88vPGPSmBE7WqZF5I84IJ7wzwpRs+ifz9DfpFqWzj55mftTHQERWDhcKRALgdZECoFCqtmNhRFERxAm+MrIkypZG/JAdcho0cLyIGTkw7KLqKT0/NmQgQ3vsi6IxGOF4u8gPfLHfRkLopZkU7sXXHNC5hVtEmGXz0zrp+Pq9diKIX6MyrAtwjhIxxKu5iI9MO7XB272hpeonpJYWA0dvh0F882tjNnN6oRJrQ1ZxPXfeA"}
You may refer to the pseudo code below for the signature generation:
message = clientID + signatureMethod + timestamp + nonce + request_body
sha256_HMAC = Mac.getInstance("HmacSHA256");
secret_key = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
sha256_HMAC.init(secret_key);
hash = Base64.encodeBase64String(sha256_HMAC.doFinal(message.getBytes()));
// If the hash needs to be URL encoded
signature = URLEncoder.encode(hash, "UTF-8")
With the parameters provided you should get the following result:
17uX5GHbU7x1mz1czXBLifRqOJ%2BwzZG105bj%2FWpuwU0%3D
Now construct the request header with all the parameters:
{
"clientID": "clientID20220817demo",
"signatureMethod": "HmacSHA256",
"timestamp": 1660721425291,
"nonce": "nonce20220817",
"signature": "17uX5GHbU7x1mz1czXBLifRqOJ%2BwzZG105bj%2FWpuwU0%3D"
}
The completed request should be like following:
[Post] https:///api/v1/auth/getToken
// Request Header
{ "clientID": "clientID20220817demo",
"signatureMethod": "HmacSHA256",
"timestamp": 1660721425291,
"nonce": "nonce20220817",
"signature": "17uX5GHbU7x1mz1czXBLifRqOJ%2BwzZG105bj%2FWpuwU0%3D" }
// Request Body
{"content": "AAAADLzOxAK6KCtIQgl/BJRVECazUaNiaf13rfcGNApA3K0BI0qZkB5pMWAjcTF0z0PLOnsCyxCtVUytAbA/cm2U5W83FrRXvtZZ74SrCWY4cQiAlq38TLSeOY9B418Tc5dUr1JnbCVeHe8HNrEY81QyI3r7JMZfXGaWgRoz0os8C7zbzty88vPGPSmBE7WqZF5I84IJ7wzwpRs+ifz9DfpFqWzj55mftTHQERWDhcKRALgdZECoFCqtmNhRFERxAm+MrIkypZG/JAdcho0cLyIGTkw7KLqKT0/NmQgQ3vsi6IxGOF4u8gPfLHfRkLopZkU7sXXHNC5hVtEmGXz0zrp+Pq9diKIX6MyrAtwjhIxxKu5iI9MO7XB272hpeonpJYWA0dvh0F882tjNnN6oRJrQ1ZxPXfeA" }
Upon success you should receive the encrypted response:
{
"txID": "",
"code": "D00000",
"message": "SUCCESS",
“secretKey”:"AAAADLzOxAK6KCtIQgl/BJRVECazUaNiaf13rfcGNApA3K0BI0qZkB5pMWAjcTF0z0PLOnsCyxCtVUytAbA/cm2U5W83FrRXvtZZ74SrCWY4cQiAlq38TLSeOY9B418Tc5dUr1JnbCVeHe8HNrEY81QyI3r7JMZfXGaWgRoz0os8C7zbzty88vPGPSmBE7WqZF5I84IJ7wzwpRs+ifz9DfpFqWzj55mftTHQERWDhcKRALgdZECoFCqtmNhRFERxAm+MrIkypZG/JAdcho0cLyIGTkw7KLqKT0/NmQgQ3vsi6IxGOF4u8gPfLHfRkLopZkU7sXXHNC5hVtEmGXz0zrp+Pq9diKIX6MyrAtwjhIxxKu5iI9MO7XB272hpeonpJYWA0dvh0F882tjNnN6oRJrQ1ZxPXfeA",
"content":"AAAADLzOxAK6KCtIQgl/BJRVECazUaNiaf13rfcGNApA3K0BI0qZkB5pMWAjcTF0z0PLOnsCyxCtVUytAbA/cm2U5W83FrRXvtZZ74SrCWY4cQiAlq38TLSeOY9B418Tc5dUr1JnbCVeHe8HNrEY81QyI3r7JMZfXGaWgRoz0os8C7zbzty88vPGPSmBE7WqZF5I84IJ7wzwpRs+ifz9DfpFqWzj55mftTHQERWDhcKRALgdZECoFCqtmNhRFERxAm+MrIkypZG/JAdcho0cLyIGTkw7KLqKT0/NmQgQ3vsi6IxGOF4u8gPfLHfRkLopZkU7sXXHNC5hVtEmGXz0zrp+Pq9diKIX6MyrAtwjhIxxKu5iI9MO7XB272hpeonpJYWA0dvh0F882tjNnN6oRJrQ1ZxPXfeA"
}
Note |
Noted the secretKey used for encryption is also provided in the response body, this is for when the request hits the time of updating the CEK, an old CEK is used to Encrypted the request, in this scenario online service may use the provide secretKey in the request body for decryption. |
Decryption
The structure of the encrypted content of response body is the same as the encrypted request body:
4 bytes IV length + IV + ciphertext
To decrypt the encrypted content, you will have to locate the following data:
- 4 bytes IV length
- IV
- ciphertext
- authTag (if necessary)
You may refer to the pseudo code below for the decryption implementation:
private static final String AES_GCM_NOPADDING = "AES/GCM/NoPadding";
/**
* AES GCM encryption
* @param contentByte - Bytes of content to be encrypted
* @param key - CEK (AES 256)
* @return
*/
public static String encrypt(byte[] contentByte, byte[] key) {
SecretKeySpec skeySpec = new SecretKeySpec(key, AES);
byte[] encrypted = null;
try {
SecureRandom secureRandom = new SecureRandom();
byte[] iv = new byte[12];
// do not reuse iv with the same key
secureRandom.nextBytes(iv);
Cipher cipher = Cipher.getInstance(AES_GCM_NOPADDING);
GCMParameterSpec parameterSpec = new GCMParameterSpec(128, iv);
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, parameterSpec);
encrypted = cipher.doFinal(contentByte);
ByteBuffer byteBuffer = ByteBuffer.allocate(
4 + iv.length + encrypted.length);
byteBuffer.putInt(iv.length);
byteBuffer.put(iv);
byteBuffer.put(encrypted);
byte[] cipherMessage = byteBuffer.array();
return Base64Util.base64Encode(cipherMessage);
} catch (NoSuchAlgorithmException | NoSuchPaddingException
| InvalidKeyException | InvalidAlgorithmParameterException
| IllegalBlockSizeException | BadPaddingException e) {
log.error("Encryption error: {}", e);
throw new IAMSmartException(e);
}
}
You should get the following result:
{
"txID": "",
"code": "D00000",
"message": "SUCCESS",
"content": {
"accessToken": "0ad186353c424c64897fcc00445c9ba1",
"tokenType": "Bearer",
"issueAt": 1557053922938,
"expiresIn": 14400000, // 4 hours
"openID": "liR14%2BvX%2F5hSum5uf4ERczu0KcDnIJA5BM7FoM1ag9c%3D",
"lastModifiedDate": 1560849218006,
"userType": "sign",
"scope": "eidapi_auth eidapi_formFilling"
}
}
5. User link-up First Time Log in
After getting the accessToken and tokenisedID from “iAM Smart” core system, Online Service need to check if current tokenisedID is existed in Online Service Database system and it means the link-up process has been done. If it is linked up with “iAM Smart” account, then login successfully. Otherwise, user link-up first time login process
If the Online Service uses the HKID number for user identification, then the following user link-up first time login process can be made as a reference.
5.1 User Journey

5.2 Consent Page for requesting “iAM Smart” profile
Online Service shall display a consent page before requesting the user’s “iAM Smart” profile data. The page shall explain clearly to user why such data is requires during authentication process and avoid requesting more HKIC data items than necessary. In this case, only HKID profile should be requested.
Information for Consent Page | ||
Traditional Chinese | 授權「智方便」提供個人資料 | |
Simplified Chinese | 授权「智方便」提供个人资料 | |
English | Authorise “iAM Smart” to provide personal information | |
Instructions | ||
Traditional Chinese | 歡迎你透過「智方便」登入 <你的服務名稱> 這是你首次透過「智方便」登入<你的服務名稱>,系統將要求「智方便」提供以下個人資料,以便為您連結原有帳號/開立新帳號: – 英文姓名 – 中文姓名 – 出生日期 – 性別 – 身份證號碼 | |
Simplified Chinese | 欢迎你透过「智方便」登入 <你的服务名称> 这是你首次透过「智方便」登入<你的服务名称>,系统将要求「智方便」提供以下个人资料,以便为您连结原有帐号/开立新帐号: – 英文姓名 – 中文姓名 – 出生日期 – 性别 – 身份证号码 | |
English | Welcome to log in to <Online Service Name> through “iAM Smart” This is the first time you have logged in to <Online Service Name> through “iAM Smart”. The system will request the following personal information via “iAM Smart” for linking up your existing account or creating a new account: – English Name – Chinese Name – Gender – HKID number |
5.3 Require Profile
Composing Request Body and Request Header
Parameter | Type | Presence | Description |
businessID | String | Required | businessID is a unique identifier for Online Service to differentiate different request. It should be ASCII string with length less than or equal to 36 chars. |
accessToken | String | Required | accessToken value |
openID | String | Required | Tokenised ID value |
source | String | Required | Request initiator. The supported source values can be found in Appendix B of this specification. |
redirectURI | String | Required | callback URI. |
state | String | Optional | If state parameter is presented in the request message, the same state value will be returned to Online Service during callback. It is used to prevent the CSRF attack. The value of state is defined by Online Service and it should be a secure random string of any length less than or equal to 36 (UUID string length). Only ASCII letters, numbers, underscore and hyphen are accepted. |
profileFields | Array | Required | Specify the profile fields to be requested. The available profileFields are as follows: profileFields Description idNo ID number enName English name chName Chinese name birthDate Date of birth gender gender |
Your request body should look something like this:
// How to generate shared common parameters is described in 4.5.2
POST
https:///api/v1/auth/profile/initiateRequest
// Request Headers
clientID: "edae2e2529ff46228af1e4d18c8405d1"
signatureMethod: "HmacSHA256"
signature: "5X42Y1B7MEd8Mm%2BonwjiQz9VCZkkrntADskXsYntavU%3D"
timestamp: 1557048906183
nonce: "e893647dc4204eb9b7b8eddd527b687c"
// Request Body
{
"businessID": "bbb8aae57c104cda40c93843ad5e6db8",
"accessToken": "xxxa42e76bf4cb0846a68e6d83d6096",
"openID": "liR14%2BvX%2F5hSum5uf4ERczu0KcDnIJA5BM7FoM1ag9c%3D",
"source": "Android_Chrome",
"redirectURI": "https:////",
"state": "eddd527b6",
" profileFields": ["idNo", "enName"]
}
Encryption
As an additional layer of data encryption will be applied to all APIs POST request, please follow section 4.5.1.1 to construct the encrypted request header and request body.
Upon success you should receive the encrypted response:
{
"txID": "",
"code": "D00000",
"message": "SUCCESS",
“secretKey”:"AAAADLzOxAK6KCtIQgl/BJRVECazUaNiaf13rfcGNApA3K0BI0qZkB5pMWAjcTF0z0PLOnsCyxCtVUytAbA/cm2U5W83FrRXvtZZ74SrCWY4cQiAlq38TLSeOY9B418Tc5dUr1JnbCVeHe8HNrEY81QyI3r7JMZfXGaWgRoz0os8C7zbzty88vPGPSmBE7WqZF5I84IJ7wzwpRs+ifz9DfpFqWzj55mftTHQERWDhcKRALgdZECoFCqtmNhRFERxAm+MrIkypZG/JAdcho0cLyIGTkw7KLqKT0/NmQgQ3vsi6IxGOF4u8gPfLHfRkLopZkU7sXXHNC5hVtEmGXz0zrp+Pq9diKIX6MyrAtwjhIxxKu5iI9MO7XB272hpeonpJYWA0dvh0F882tjNnN6oRJrQ1ZxPXfeA",
"content":"AAAADLzOxAK6KCtIQgl/BJRVECazUaNiaf13rfcGNApA3K0BI0qZkB5pMWAjcTF0z0PLOnsCyxCtVUytAbA/cm2U5W83FrRXvtZZ74SrCWY4cQiAlq38TLSeOY9B418Tc5dUr1JnbCVeHe8HNrEY81QyI3r7JMZfXGaWgRoz0os8C7zbzty88vPGPSmBE7WqZF5I84IJ7wzwpRs+ifz9DfpFqWzj55mftTHQERWDhcKRALgdZECoFCqtmNhRFERxAm+MrIkypZG/JAdcho0cLyIGTkw7KLqKT0/NmQgQ3vsi6IxGOF4u8gPfLHfRkLopZkU7sXXHNC5hVtEmGXz0zrp+Pq9diKIX6MyrAtwjhIxxKu5iI9MO7XB272hpeonpJYWA0dvh0F882tjNnN6oRJrQ1ZxPXfeA"
}
Note |
Noted the secretKey used for encryption is also provided in the response body, this is for when the request hits the time of updating the CEK, an old CEK is used to encrypt the request, in this scenario online service may use the provided secretKey in the request body for decryption. |
Decryption
Please refer to section 4.5.2.1 for decryption of the content data, and you should get the following result:
{
"txID": "",
"code": "D00000",
"message": "SUCCESS",
"content": {
"authByQR": true
}
}
5.4 Instruction Page for requesting “iAM Smart” Profile
After Online Service sends the getting “iAM Smart” profile data request to “iAM Smart” system, Online Service is required to instruct to open the “iAM Smart” app in his/her mobile phone. Please refer to the table below for different scenarios.
Same Device | Different Device | |
Information | ||
Traditional Chinese | 授權「智方便」提供個人資料 | |
Simplified Chinese | 授权「智方便」提供个人资料 | |
English | Authorise “iAM Smart” to provide personal information | |
Instructions | ||
Traditional Chinese | 請按照以下步驟:
| 請按照以下步驟:
|
Simplified Chinese | 请按照以下步骤:
| 请按照以下步骤:
|
English | Please follow the steps below:
| Please follow the steps below:
|
Example | ||
Remark: The font colour of step 1 above must be green (#2B7366) for consistency with “iAM Smart”. |
5.5 Callback to Receive iAM Smart Profile
After client authorizing the getting profile request, “iAM Smart” core system will redirect to Online Service callback URL with “iAM Smart” profile data.
Callback Parameters
Parameter | Type | Presence | Description | |
businessID | String | Required | businessID is a unique identifier for Online Service to differentiate different request. Online Service can use the businessID to relate the callback message with the original request. | |
state | String | Optional | If the state parameter has been present in the request message, the exact value of state will be returned. It is used to prevent the CSRF attack. The value of state is defined by Online Service and it should be a secure random value. | |
idNo | JSON Object | Optional | ID number | |
enName | JSON Object | Optional | English name | |
chName | JSON Object | Optional | Chinese name | |
birthDate | String | Optional | Date of birth | |
gender | String | Optional | gender | |
chNameVerified | String | Optional | ImmD characters code point will be returned to Online Service if Chinese name verified. |
Upon success you should receive the encrypted response:
{
"txID": "",
"code": "D00000",
"message": "SUCCESS",
“secretKey”:"AAAADLzOxAK6KCtIQgl/BJRVECazUaNiaf13rfcGNApA3K0BI0qZkB5pMWAjcTF0z0PLOnsCyxCtVUytAbA/cm2U5W83FrRXvtZZ74SrCWY4cQiAlq38TLSeOY9B418Tc5dUr1JnbCVeHe8HNrEY81QyI3r7JMZfXGaWgRoz0os8C7zbzty88vPGPSmBE7WqZF5I84IJ7wzwpRs+ifz9DfpFqWzj55mftTHQERWDhcKRALgdZECoFCqtmNhRFERxAm+MrIkypZG/JAdcho0cLyIGTkw7KLqKT0/NmQgQ3vsi6IxGOF4u8gPfLHfRkLopZkU7sXXHNC5hVtEmGXz0zrp+Pq9diKIX6MyrAtwjhIxxKu5iI9MO7XB272hpeonpJYWA0dvh0F882tjNnN6oRJrQ1ZxPXfeA",
"content":"AAAADLzOxAK6KCtIQgl/BJRVECazUaNiaf13rfcGNApA3K0BI0qZkB5pMWAjcTF0z0PLOnsCyxCtVUytAbA/cm2U5W83FrRXvtZZ74SrCWY4cQiAlq38TLSeOY9B418Tc5dUr1JnbCVeHe8HNrEY81QyI3r7JMZfXGaWgRoz0os8C7zbzty88vPGPSmBE7WqZF5I84IJ7wzwpRs+ifz9DfpFqWzj55mftTHQERWDhcKRALgdZECoFCqtmNhRFERxAm+MrIkypZG/JAdcho0cLyIGTkw7KLqKT0/NmQgQ3vsi6IxGOF4u8gPfLHfRkLopZkU7sXXHNC5hVtEmGXz0zrp+Pq9diKIX6MyrAtwjhIxxKu5iI9MO7XB272hpeonpJYWA0dvh0F882tjNnN6oRJrQ1ZxPXfeA"
}
Note |
Noted the secretKey used for encryption is also provided in the response body, this is for when the request hits the time of updating the CEK, an old CEK is used to encrypt the request, in this scenario online service may use the provided secretKey in the request body for decryption. |
Decryption
Please refer to section 4.5.2.1 for decryption of the content data, and you should get the following result:
POST
https:////
// Callback Body
{
"txID": "",
"code": "D00000",
"message": "SUCCESS",
"content": {
"businessID": "3e47be25-66a6-43fb-89f6-7e2dd138aff8",
"state": "unesidkd",
"idNo": {
"Identification": "A123456",
"CheckDigit": "A"
},
"enName": {
"UnstructuredName": "SAN, Chi Nan"
},
"chName": {
"ChineseName": "申智能"
},
"birthDate": "19960000",
"gender": "M",
"chNameVerified": "申智能"
}
}
After successfully getting the HKID from “iAM Smart” profile, Online Service then should handle the HKID matching process, if it is matched, then should bind the Online Service account with “iAM Smart” account by the tokenisedID. After binding successfully, the user link-up first time log in successfully page should be displayed.

Note |
For each Online Service, each user will have a unique tokenisedID. When it comes to another Online Service, the tokenisedID will be different. |
6. User Registration
If the user cannot be matched with HKID which means that current user is not a user in Online Service system, then the user registration process should be processed.
The following scenario can be made as a reference when the Online Service use “iAM Smart” Form Filling function to fill the input for personal data of the user. (eg. Name, Gender, Email, Phone Number and so on.)
6.1 User Journey

6.2 Flow
Please find below the sequence diagram of the whole form filling process:

6.3 Click “iAM Smart” Button in initiation page
Online Service shall display one of the following button depends on the scenario:
Form Filling button | ||
Usage | The button for user to initiate the authorisation flow. | |
With “iAM Smart” profile | No | Yes (For user verification purpose) |
Button Description | ||
Traditional Chinese | 智方便填表通 | 智方便個人資料 |
Simplified Chinese | 智方便填表通 | 智方便个人资料 |
English | Form Filling with iAM Smart e-ME | Personal Data from iAM Smart |
Sample Button | ||
Traditional Chinese | ![]() | ![]() |
Simplified Chinese | ![]() | ![]() |
English | ![]() | ![]() |
Tip |
Please note that the request shall be initiated after the user clicked the “Form Filling with iAM Smart e-Me” or “Personal Data from iAM Smart” button. |
Without profileFields | With profileFields |
If only eMeFields is required in this request, online service shall use “Form Filling with iAM Smart e-ME” and no consent page is required | Online Service shall display a consent page before calling the API for form filling to get the “iAM Smart” profile data. The page shall clearly explain to user why such data are required for the business operations (e.g. account activation, account creation, etc.) and avoid requesting more HKIC data items than necessary. For Content page and More info link, please refer to section 1.3 and section 1.4. |
6.4 Submit “Request Form Filling” with access token, tokenized ID
6.4.1 Composing Request Body
Parameter | Type | Presence | Description |
businessID | String | Required | businessID is a unique identifier for Online Service to differentiate different request. It should be ASCII string with length less than or equal to 36 chars. |
accessToken | String | Required | accessToken value |
openID | String | Required | Tokenised ID value |
source | String | Required | Request initiator. The supported source values can be found in Appendix B of this specification. |
redirectURI | String | Required | callback URI. |
state | String | Optional | If state parameter is presented in the request message, the same state value will be returned to Online Service during callback. It is used to prevent the CSRF attack. The value of state is defined by Online Service and it should be a secure random string of any length less than or equal to 36 (UUID string length). Only ASCII letters, numbers, underscore and hyphen are accepted. |
formName | String | Optional | The name of the form should be encoded in Unicode. The maximun length can be found in part C of the Appendix in this specification. |
formNum | String | Optional | The number of the form should be encoded in Unicode. The maximun length can be found in part C of the Appendix in this specification. |
formDesc | String | Optional | The description of the form should beencoded in Unicode. The maximun length can be found in part C of the Appendix in this specification. |
eMEFields | Array | Required (Conditional) | Specify the e-ME fields to be requested. If eMEFields and the following profileFields are not provided or are empty arrays, the HTTP code 200 with error code D20002 (empty parameter {eMEFields,profileFields}) will be returned. The available eMEFields are as follows: eMEFields Description idNo ID number prefix prefix enName English name chName Chinese name birthDate Date of birth gender gender maritalStatus marital status homeTelNumber home telephone number officeTelNumber office telephone number mobileNumber mobile number emailAddress email address residentialAddress residential address postalAddress postal address educationLevel education level addressDocInfo provider name, retrieval date, owner name and address information related to an e-bill addressDocFile e-bill from an address data provider |
profileFields | Array | Required (Conditional) | Specify the profile fields to be requested. If profileFields and the above eMEFields are not provided or are empty arrays, the HTTP code 200 with error code D20002 (empty parameter {eMEFields,profileFields}) will be returned. The available profileFields are as follows: profileFields Description idNo ID number enName English name chName Chinese name birthDate Date of birth gender gender |
You request body should look something like this:
https:///api/v2/account/formFilling/initiateRequest
// Request Headers
clientID: "edae2e2529ff46228af1e4d18c8405d1"
signatureMethod: "HmacSHA256"
signature: "5X42Y1B7MEd8Mm%2BonwjiQz9VCZkkrntADskXsYntavU%3D"
timestamp: 1557048906183
nonce: "e893647dc4204eb9b7b8eddd527b687c"
// Request Body
{
"businessID": "bbb8aae57c104cda40c93843ad5e6db8",
"accessToken": "xxxa42e76bf4cb0846a68e6d83d6096",
"openID": "liR14%2BvX%2F5hSum5uf4ERczu0KcDnIJA5BM7FoM1ag9c%3D",
"source": "Android_Chrome",
"redirectURI": "https:////",
"state": "eddd527b6",
"formName": "Example Account Registration Form",
"formNum": "APP0001",
"formDesc": "Example form description",
"profileFields": ["idNo", "enName", "gender", "chName", "birthDate"],
"eMEFields": ["mobileNumber", " emailAddress", "addressDocInfo"]
}
6.4.2 Encryption
As an additional layer of data encryption will be applied to all APIs POST request, please follow section 4.5.1.1 to construct the encrypted request header and request body.
Upon success you should receive the encrypted response:
{
"txID": "",
"code": "D00000",
"message": "SUCCESS",
“secretKey”:"AAAADLzOxAK6KCtIQgl/BJRVECazUaNiaf13rfcGNApA3K0BI0qZkB5pMWAjcTF0z0PLOnsCyxCtVUytAbA/cm2U5W83FrRXvtZZ74SrCWY4cQiAlq38TLSeOY9B418Tc5dUr1JnbCVeHe8HNrEY81QyI3r7JMZfXGaWgRoz0os8C7zbzty88vPGPSmBE7WqZF5I84IJ7wzwpRs+ifz9DfpFqWzj55mftTHQERWDhcKRALgdZECoFCqtmNhRFERxAm+MrIkypZG/JAdcho0cLyIGTkw7KLqKT0/NmQgQ3vsi6IxGOF4u8gPfLHfRkLopZkU7sXXHNC5hVtEmGXz0zrp+Pq9diKIX6MyrAtwjhIxxKu5iI9MO7XB272hpeonpJYWA0dvh0F882tjNnN6oRJrQ1ZxPXfeA",
"content":"AAAADLzOxAK6KCtIQgl/BJRVECazUaNiaf13rfcGNApA3K0BI0qZkB5pMWAjcTF0z0PLOnsCyxCtVUytAbA/cm2U5W83FrRXvtZZ74SrCWY4cQiAlq38TLSeOY9B418Tc5dUr1JnbCVeHe8HNrEY81QyI3r7JMZfXGaWgRoz0os8C7zbzty88vPGPSmBE7WqZF5I84IJ7wzwpRs+ifz9DfpFqWzj55mftTHQERWDhcKRALgdZECoFCqtmNhRFERxAm+MrIkypZG/JAdcho0cLyIGTkw7KLqKT0/NmQgQ3vsi6IxGOF4u8gPfLHfRkLopZkU7sXXHNC5hVtEmGXz0zrp+Pq9diKIX6MyrAtwjhIxxKu5iI9MO7XB272hpeonpJYWA0dvh0F882tjNnN6oRJrQ1ZxPXfeA"
}
Note |
Noted the secretKey used for encryption is also provided in the response body, this is for when the request hits the time of updating the CEK, an old CEK is used to encrypt the request, in this scenario online service may use the provided secretKey in the request body for decryption. |
6.4.3 Decryption
Please refer to section 1.2 for decryption of the content data, and you should get the following result:
{
"txID": "",
"code": "D00000",
"message": "SUCCESS",
"content": {
"authByQR": true
}
}
6.4.4 Acknowledge Form Filling request
6.4.5 Callback with authorized Form Filling Result
After user confirming the authorisation, “iAM Smart” core system will redirect to Online Service callback URL with authCode.
Callback Parameters
Parameter | Type | Presence | Description |
businessID | String | Required | businessID is a unique identifier for Online Service to differentiate different request. Online Service can use the businessID to relate the callback message with the original request. |
state | String | Optional | If the state parameter has been present in the request message, the exact value of state will be returned. It is used to prevent the CSRF attack. The value of state is defined by Online Service and it should be a secure random value. |
idNo | JSON Object | Optional | HKIC number |
prefix | String | Optional | prefix |
enName | JSON Object | Optional | English name |
chName | JSON Object | Optional | Chinese name |
birthDate | String | Optional | Date of birth |
gender | String | Optional | gender |
maritalStatus | String | Optional | marital status |
homeTelNumber | JSON Object | Optional | home telephone number |
officeTelNumber | JSON Object | Optional | office telephone number |
mobileNumber | JSON Object | Optional | mobile number |
emailAddress | String | Optional | email address |
residentialAddress | JSON Object | Optional | residential address |
postalAddress | JSON Object | Optional | postal address |
educationLevel | String | Optional | education level |
chNameVerified | String | Optional | ImmD characters code point will be returned to Online Service if Chinese name verified. |
addressDocInfo | JSON Object | Optional | the data related to the obtained e-bill, including the provider name, retrieval date, owner name, service address and postal address. The sub-field lastRetrievalDate refers to the date and time at which iAM Smart obtained the e-bill. The schema of sub-fields is given in Appendix A. |
addressDocFile | JSON Object | Optional | the e-bill obtained from an address data provider. Sub-fields include the PDF e-bill file (docFile), the SHA256 hash (docHash) and the bill date of the e-bill (billDate). The schema of sub-fields is given in Appendix A. |
Upon success you should receive the encrypted response:
{
"txID": "",
"code": "D00000",
"message": "SUCCESS",
“secretKey”:"AAAADLzOxAK6KCtIQgl/BJRVECazUaNiaf13rfcGNApA3K0BI0qZkB5pMWAjcTF0z0PLOnsCyxCtVUytAbA/cm2U5W83FrRXvtZZ74SrCWY4cQiAlq38TLSeOY9B418Tc5dUr1JnbCVeHe8HNrEY81QyI3r7JMZfXGaWgRoz0os8C7zbzty88vPGPSmBE7WqZF5I84IJ7wzwpRs+ifz9DfpFqWzj55mftTHQERWDhcKRALgdZECoFCqtmNhRFERxAm+MrIkypZG/JAdcho0cLyIGTkw7KLqKT0/NmQgQ3vsi6IxGOF4u8gPfLHfRkLopZkU7sXXHNC5hVtEmGXz0zrp+Pq9diKIX6MyrAtwjhIxxKu5iI9MO7XB272hpeonpJYWA0dvh0F882tjNnN6oRJrQ1ZxPXfeA",
"content":"AAAADLzOxAK6KCtIQgl/BJRVECazUaNiaf13rfcGNApA3K0BI0qZkB5pMWAjcTF0z0PLOnsCyxCtVUytAbA/cm2U5W83FrRXvtZZ74SrCWY4cQiAlq38TLSeOY9B418Tc5dUr1JnbCVeHe8HNrEY81QyI3r7JMZfXGaWgRoz0os8C7zbzty88vPGPSmBE7WqZF5I84IJ7wzwpRs+ifz9DfpFqWzj55mftTHQERWDhcKRALgdZECoFCqtmNhRFERxAm+MrIkypZG/JAdcho0cLyIGTkw7KLqKT0/NmQgQ3vsi6IxGOF4u8gPfLHfRkLopZkU7sXXHNC5hVtEmGXz0zrp+Pq9diKIX6MyrAtwjhIxxKu5iI9MO7XB272hpeonpJYWA0dvh0F882tjNnN6oRJrQ1ZxPXfeA"
}
Note |
Noted the secretKey used for encryption is also provided in the response body, this is for when the request hits the time of updating the CEK, an old CEK is used to encrypt the request, in this scenario online service may use the provided secretKey in the request body for decryption. |
Decryption
Please refer to section 1.2 for decryption of the content data, and you should get the following result:
POST
https:////
// Callback Body
{
"txID": "",
"code": "D00000",
"message": "SUCCESS",
"content": {
"businessID": "2YotnFZFEjr1zCsicMWpAA",
"idNo": {
"Identification": "A123456",
"CheckDigit": "A"
},
"prefix": "Mr",
"enName": {
"UnstructuredName": "SAN, Chi Nan"
},
"chName": {
"ChineseName": "申智能"
},
"chNameVerified": "申智能",
// May be 19960000 or 19960100
"birthDate": "19960128",
"gender": "M",
"maritalStatus": "S",
"homeTelNumber": {
"CountryCode": "852",
"SubscriberNumber": "98765432"
},
"officeTelNumber": {
"CountryCode": "1",
"SubscriberNumber": "123456"
},
"mobileNumber": {
"CountryCode": "1",
"SubscriberNumber": "98765432"
},
6.4.6 Display/Fill the form Filling request
When an online service adopts “iAM Smart” form filling, the fields filled with data from “iAM Smart” shall be marked with a tag of “iAM Smart”*.
The fields filled with data from “iAM Smart” profile shall not be editable.
The “iAM Smart” tag for the field filled with data from “iAM Smart” or “e-ME” shall be removed once the user modifies the filled data in the form.
without profileFields | With profileFields |
After successfully getting all the information needed to create Online Service account, Online Service then can help the client to create the account and auto link up with iAM Smart account. Online Service should pop up the page to remind client account has been created successfully and client can use “iAM Smart” for future login.