@opengovsg/mockpass 4.8.1 → 4.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -125,6 +125,7 @@ MockPass accepts any value for `client_id` and `redirect_uri`.
125
125
  | Client signing and encryption keys | **Overview:** When client makes any request, what signing key is used to verify the client's signature on the client assertion, and what encryption key is used to encrypt the data payload. <br> **Default:** static keyset `static/certs/oidc-v2-rp-public.json` is used. <br> **How to configure:** Set the env var `SP_RP_JWKS_ENDPOINT` to a JWKS URL that MockPass can connect to. This can be a HTTP or HTTPS URL. |
126
126
  | Login page | **Overview:** When client makes an authorize request, whether MockPass sends the client to a login page, instead of completing the login silently. <br> **Default:** Disabled for all requests. <br> **How to configure:** Enable for all requests by default by setting the env var `SHOW_LOGIN_PAGE` to `true`. Regardless of the default, you can override on a per-request basis by sending the HTTP request header `X-Show-Login-Page` with the value `true`. <br> **Detailed effect:** When login page is disabled, MockPass will immediately complete login and redirect to the `redirect_uri`. The profile used will be (in order of decreasing precedence) the profile specified in HTTP request headers (`X-Custom-NRIC` and `X-Custom-UUID` must both be specified), the profile with the NRIC specified in the env var `MOCKPASS_NRIC`, or the first profile in MockPass' static data. <br> When login page is enabled, MockPass returns a HTML page with a form that is used to complete the login. The client may select an existing profile, or provide a custom NRIC and UUID on the form. |
127
127
  | ID token exchange | **Overview:** Singpass uses the client's [profile](https://docs.developer.singpass.gov.sg/docs/technical-specifications/singpass-authentication-api/2.-token-endpoint/authorization-code-grant#id-token-structure) to decide the format of the id token to send across. <br> **Default:** `direct` <br> **How to configure:** To set this, set the env var (`SINGPASS_CLIENT_PROFILE`) to the desired value |
128
+ | Test users/profiles | **Overview:** The list of NRIC/UUID (and, for foreign IDs, `sfa`) profiles MockPass can log in as. <br> **Default:** static data `static/singpass/users.json` is used. <br> **How to configure:** Set the env var `SINGPASS_USERS_PATH` to the path to a JSON file with the same shape (an array of `{ nric, uuid }`, optionally `sfa: { fid, coi, RP }` for NRICs starting with `Y`). An absolute path is recommended. |
128
129
 
129
130
  ### Corppass v2 (Corppass OIDC)
130
131
 
@@ -148,6 +149,7 @@ MockPass accepts any value for `client_id` and `redirect_uri`.
148
149
  | ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
149
150
  | Client signing and encryption keys | **Overview:** When client makes any request, what signing key is used to verify the client's signature on the client assertion, and what encryption key is used to encrypt the data payload. <br> **Default:** static keyset `static/certs/oidc-v2-rp-public.json` is used. <br> **How to configure:** Set the env var `CP_RP_JWKS_ENDPOINT` to a JWKS URL that MockPass can connect to. This can be a HTTP or HTTPS URL. |
150
151
  | Login page | **Overview:** When client makes an authorize request, whether MockPass sends the client to a login page, instead of completing the login silently. <br> **Default:** Disabled for all requests. <br> **How to configure:** Enable for all requests by default by setting the env var `SHOW_LOGIN_PAGE` to `true`. Regardless of the default, you can override on a per-request basis by sending the HTTP request header `X-Show-Login-Page` with the value `true`. <br> **Detailed effect:** When login page is disabled, MockPass will immediately complete login and redirect to the `redirect_uri`. The profile used will be (in order of decreasing precedence) the profile specified in HTTP request headers (`X-Custom-NRIC`, `X-Custom-UUID`, `X-Custom-UEN` must all be specified), the profile with the NRIC specified in the env var `MOCKPASS_NRIC`, or the first profile in MockPass' static data. <br> When login page is enabled, MockPass returns a HTML page with a form that is used to complete the login. The client may select an existing profile, or provide a custom NRIC, UUID and UEN on the form. |
152
+ | Test users/profiles | **Overview:** The list of NRIC/UUID/UEN profiles MockPass can log in as. <br> **Default:** static data `static/corppass/users.json` is used. <br> **How to configure:** Set the env var `CORPPASS_USERS_PATH` to the path to a JSON file with the same shape (an array of `{ nric, uuid, name, isSingPassHolder, uen }`). An absolute path is recommended. |
151
153
 
152
154
  ### Myinfo v3
153
155
 
@@ -176,11 +178,12 @@ Only the profiles (NRICs) that have entries in Mockpass' personas dataset will
176
178
  succeed, using other NRICs will result in an error. See the list of personas in
177
179
  [static/myinfo/v3.json](static/myinfo/v3.json).
178
180
 
179
- | Configuration item | Explanation |
180
- | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
181
- | Client certificate | **Overview:** When client makes any request, what certificate is used to verify the request signature, and what certificate is used to encrypt the data payload. <br> **Default:** static certificate/key `static/certs/(server.crt\|key.pub)` are used. <br> **How to configure:** Set the env var `SERVICE_PROVIDER_PUB_KEY` to the path to a public key PEM file, and `SERVICE_PROVIDER_CERT_PATH` to the path to a certificate PEM file. (A certificate PEM file can also be provided to `SERVICE_PROVIDER_PUB_KEY`, despite the env var name.) |
182
- | Client secret | **Overview:** When client makes a Token request, whether MockPass verifies the request signature. <br> **Default:** Disabled. <br> **How to configure:** Enable for all requests by setting the env var `SERVICE_PROVIDER_MYINFO_SECRET` to some non-blank string. Provide this value to your application as well. |
183
- | Payload encryption | **Overview:** When client makes a Person or Person-Basic request, whether MockPass encrypts the data payload. When client makes a Person request, whether MockPass verifies the request signature. <br> **Default:** Disabled. <br> **How to configure:** Enable for all requests by setting the env var `ENCRYPT_MYINFO` to `true`. |
181
+ | Configuration item | Explanation |
182
+ | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
183
+ | Client certificate | **Overview:** When client makes any request, what certificate is used to verify the request signature, and what certificate is used to encrypt the data payload. <br> **Default:** static certificate/key `static/certs/(server.crt\|key.pub)` are used. <br> **How to configure:** Set the env var `SERVICE_PROVIDER_PUB_KEY` to the path to a public key PEM file, and `SERVICE_PROVIDER_CERT_PATH` to the path to a certificate PEM file. (A certificate PEM file can also be provided to `SERVICE_PROVIDER_PUB_KEY`, despite the env var name.) |
184
+ | Client secret | **Overview:** When client makes a Token request, whether MockPass verifies the request signature. <br> **Default:** Disabled. <br> **How to configure:** Enable for all requests by setting the env var `SERVICE_PROVIDER_MYINFO_SECRET` to some non-blank string. Provide this value to your application as well. |
185
+ | Payload encryption | **Overview:** When client makes a Person or Person-Basic request, whether MockPass encrypts the data payload. When client makes a Person request, whether MockPass verifies the request signature. <br> **Default:** Disabled. <br> **How to configure:** Enable for all requests by setting the env var `ENCRYPT_MYINFO` to `true`. |
186
+ | Personas/test users | **Overview:** The dataset of NRIC-keyed personas (Myinfo attribute values, and the UUID/profile used for login) that MockPass serves. <br> **Default:** static data `static/myinfo/v3.json` is used. <br> **How to configure:** Set the env var `MYINFO_V3_USERS_PATH` to the path to a JSON file with the same shape (`{ attributes, personas }`, where `personas` is keyed by NRIC). An absolute path is recommended. |
184
187
 
185
188
  To emulate the equivalent of the Test environment on Myinfo v3, you must both
186
189
  set a client secret and enable payload encryption on MockPass.
@@ -209,7 +212,8 @@ MockPass accepts any value for `client_id`, `client_secret` and `redirect_uri`.
209
212
 
210
213
  Only the profiles (NRICs) that have entries in Mockpass' personas dataset will
211
214
  succeed, using other NRICs will result in an error. See the list of personas in
212
- [static/myinfo/v3.json](static/myinfo/v3.json).
215
+ [static/myinfo/v3.json](static/myinfo/v3.json), or the env var
216
+ `MYINFO_V3_USERS_PATH` to override it (see the Myinfo v3 section above).
213
217
 
214
218
  If the Public Officer Employment Details data item is requested, the
215
219
  `pocdex.public_officer_details` scope data is sourced from the
package/lib/assertions.js CHANGED
@@ -24,131 +24,43 @@ const hashToken = (token) => {
24
24
  }
25
25
 
26
26
  const myinfo = {
27
- v3: JSON.parse(readFrom('../static/myinfo/v3.json')),
27
+ v3: JSON.parse(
28
+ readFrom(process.env.MYINFO_V3_USERS_PATH || '../static/myinfo/v3.json'),
29
+ ),
28
30
  }
29
31
 
32
+ const singPassUsers = JSON.parse(
33
+ readFrom(process.env.SINGPASS_USERS_PATH || '../static/singpass/users.json'),
34
+ )
35
+ const corpPassUsers = JSON.parse(
36
+ readFrom(process.env.CORPPASS_USERS_PATH || '../static/corppass/users.json'),
37
+ )
38
+
30
39
  const oidc = {
31
40
  singPass: [
32
- { nric: 'S8979373D', uuid: 'a9865837-7bd7-46ac-bef4-42a76a946424' },
33
- { nric: 'S8116474F', uuid: 'f4b70aea-d639-4b79-b8d9-8ace5875f6b1' },
34
- { nric: 'S8723211E', uuid: '178478de-fed7-4c03-a75e-e68c44d0d5f0' },
35
- { nric: 'S5062854Z', uuid: '1bd2e743-8681-4079-a557-6a66a8d16386' },
36
- { nric: 'T0066846F', uuid: '14f7ee8f-9e64-4170-a529-e55ca7578e2b' },
37
- { nric: 'F9477325W', uuid: '2135fe5c-d07b-49d3-b960-aabb0ff2e05a' },
38
- { nric: 'S3000024B', uuid: 'b5630beb-e3ee-4a31-aec5-534cdc087fd8' },
39
- { nric: 'S6005040F', uuid: '6c6745d9-e6c5-40ee-8c96-5d737ddbc5e4' },
40
- { nric: 'S6005041D', uuid: 'bd3fd1e0-c807-4b07-bbe4-b567cab54b8c' },
41
- { nric: 'S6005042B', uuid: '2dd788c0-d11f-4d5b-99af-b89d2389b474' },
42
- { nric: 'S6005043J', uuid: 'eb196477-36b3-4c0f-ae5e-2172e2f6a6d8' },
43
- { nric: 'S6005044I', uuid: '843ebc6b-1de1-4d46-b1dd-9ad4aeac3a27' },
44
- { nric: 'S6005045G', uuid: 'caafaedc-f369-498a-9e35-27e9cb7f0de2' },
45
- { nric: 'S6005046E', uuid: 'f9b37d06-de3f-4c4f-8331-37a3b2ee6cb4' },
46
- { nric: 'S6005047C', uuid: '57620e0f-fdf9-4f3e-a8f6-f6088e151395' },
47
- { nric: 'S6005064C', uuid: '80952b2f-3455-4b59-b50f-39afbc418271' },
48
- { nric: 'S6005065A', uuid: '3af48e26-69a1-43e3-b5f2-303098ef3210' },
49
- { nric: 'S6005066Z', uuid: '8b2f8213-2fe9-493a-ac95-0b55e319e689' },
50
- { nric: 'S6005037F', uuid: 'ae3d1d8c-6d14-449e-8ed1-9ce3d5e67607' },
51
- { nric: 'S6005038D', uuid: '23d3bb45-a324-46d6-b0d9-2e94194ed9ae' },
52
- { nric: 'S6005039B', uuid: '9ac807a2-5217-417a-a8d1-d7018b002b3f' },
53
- { nric: 'G1612357P', uuid: 'eb125a02-3137-486f-9262-eab3e0c57a5f' },
54
- { nric: 'G1612358M', uuid: 'd821900c-663d-4552-a753-a2e1cf8d124f' },
55
- { nric: 'F1612359P', uuid: '08df8d35-600c-45fd-a812-b37a27b7856a' },
56
- { nric: 'F1612360U', uuid: '1e90b698-23af-4acb-9fb4-eb5a80f444b6' },
57
- { nric: 'F1612361R', uuid: 'bc134ee1-f104-4b26-9839-32047fecb963' },
58
- { nric: 'F1612362P', uuid: '285e8366-f3bd-48b4-8153-b47260fc9f56' },
59
- { nric: 'F1612363M', uuid: '379bc106-d3db-492c-a38e-fd27642ef47f' },
60
- { nric: 'F1612364K', uuid: '108fa3ff-c85c-461e-ba1f-8edef62b68e2' },
61
- { nric: 'F1612365W', uuid: '1275ae4e-02d2-4b09-9573-36ac610ede89' },
62
- { nric: 'F1612366T', uuid: '23c6a3a4-d9d8-445f-a588-9d91831980a6' },
63
- { nric: 'F1612367Q', uuid: '0c400961-eb00-425a-8df4-6656b0b9245a' },
64
- { nric: 'F1612358R', uuid: '45669f5c-e9ac-43c6-bcd2-9c3757f1fa1c' },
65
- { nric: 'F1612354N', uuid: 'c38ddb2d-9e5d-45c2-bb70-8ccb54fc8320' },
66
- { nric: 'F1612357U', uuid: 'f904a2b1-4b61-47e2-bdad-e2d606325e20' },
67
- { nric: 'Y4581892I', uuid: 'acf8edda-bfdf-45fc-b140-a6ec6955d857' },
68
- { nric: 'Y7654321K', uuid: '9916f054-488e-4894-8299-412e46d89e67' },
69
- { nric: 'Y1234567P', uuid: '0fdcc18f-840b-4b35-80ee-44094a6cc66f' },
41
+ ...singPassUsers,
70
42
  ...Object.keys(myinfo.v3.personas).map((nric) => ({
71
43
  nric,
72
44
  uuid: myinfo.v3.personas[nric].uuid.value,
73
45
  claims: myinfo.v3.personas[nric],
74
46
  })),
75
47
  ],
76
- corpPass: [
77
- {
78
- nric: 'S8979373D',
79
- uuid: 'a9865837-7bd7-46ac-bef4-42a76a946424',
80
- name: 'Name of S8979373D',
81
- isSingPassHolder: true,
82
- uen: '123456789A',
83
- },
84
- {
85
- nric: 'S8116474F',
86
- uuid: 'f4b70aea-d639-4b79-b8d9-8ace5875f6b1',
87
- name: 'Name of S8116474F',
88
- isSingPassHolder: true,
89
- uen: '123456789A',
90
- },
91
- {
92
- nric: 'S8723211E',
93
- uuid: '178478de-fed7-4c03-a75e-e68c44d0d5f0',
94
- name: 'Name of S8723211E',
95
- isSingPassHolder: true,
96
- uen: '123456789A',
97
- },
98
- {
99
- nric: 'S5062854Z',
100
- uuid: '1bd2e743-8681-4079-a557-6a66a8d16386',
101
- name: 'Name of S5062854Z',
102
- isSingPassHolder: true,
103
- uen: '123456789B',
104
- },
105
- {
106
- nric: 'T0066846F',
107
- uuid: '14f7ee8f-9e64-4170-a529-e55ca7578e2b',
108
- name: 'Name of T0066846F',
109
- isSingPassHolder: true,
110
- uen: '123456789B',
111
- },
112
- {
113
- nric: 'F9477325W',
114
- uuid: '2135fe5c-d07b-49d3-b960-aabb0ff2e05a',
115
- name: 'Name of F9477325W',
116
- isSingPassHolder: false,
117
- uen: '123456789B',
118
- },
119
- {
120
- nric: 'S3000024B',
121
- uuid: 'b5630beb-e3ee-4a31-aec5-534cdc087fd8',
122
- name: 'Name of S3000024B',
123
- isSingPassHolder: true,
124
- uen: '123456789C',
125
- },
126
- {
127
- nric: 'S6005040F',
128
- uuid: '6c6745d9-e6c5-40ee-8c96-5d737ddbc5e4',
129
- name: 'Name of S6005040F',
130
- isSingPassHolder: true,
131
- uen: '123456789C',
132
- },
133
- ],
48
+ corpPass: corpPassUsers,
134
49
  create: {
135
50
  singPass: (
136
- { nric, uuid },
51
+ { nric, uuid, sfa },
137
52
  iss,
138
53
  aud,
139
54
  nonce,
140
55
  accessToken = crypto.randomBytes(15).toString('hex'),
141
56
  ) => {
142
57
  let sub
143
- const sfa = {
144
- Y4581892I: { fid: 'G730Z-H5P96', coi: 'DE', RP: 'CORPPASS' },
145
- Y7654321K: { fid: '123456789', coi: 'CN', RP: 'IRAS' },
146
- Y1234567P: { fid: 'G730Z-H5P96', coi: 'MY', RP: 'CORPPASS' },
147
- }
148
58
  if (nric.startsWith('Y')) {
149
- const sfaAccount = sfa[nric]
150
- ? sfa[nric]
151
- : { fid: 'G730Z-H5P96', coi: 'DE', RP: 'CORPPASS' }
59
+ const sfaAccount = sfa || {
60
+ fid: 'G730Z-H5P96',
61
+ coi: 'DE',
62
+ RP: 'CORPPASS',
63
+ }
152
64
  sub = `s=${nric},fid=${sfaAccount.fid},coi=${sfaAccount.coi},u=${uuid}`
153
65
  } else {
154
66
  sub = `s=${nric},u=${uuid}`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengovsg/mockpass",
3
- "version": "4.8.1",
3
+ "version": "4.9.1",
4
4
  "description": "A mock SingPass/CorpPass server for dev purposes",
5
5
  "main": "app.js",
6
6
  "bin": {
@@ -0,0 +1,58 @@
1
+ [
2
+ {
3
+ "nric": "S8979373D",
4
+ "uuid": "a9865837-7bd7-46ac-bef4-42a76a946424",
5
+ "name": "Name of S8979373D",
6
+ "isSingPassHolder": true,
7
+ "uen": "123456789A"
8
+ },
9
+ {
10
+ "nric": "S8116474F",
11
+ "uuid": "f4b70aea-d639-4b79-b8d9-8ace5875f6b1",
12
+ "name": "Name of S8116474F",
13
+ "isSingPassHolder": true,
14
+ "uen": "123456789A"
15
+ },
16
+ {
17
+ "nric": "S8723211E",
18
+ "uuid": "178478de-fed7-4c03-a75e-e68c44d0d5f0",
19
+ "name": "Name of S8723211E",
20
+ "isSingPassHolder": true,
21
+ "uen": "123456789A"
22
+ },
23
+ {
24
+ "nric": "S5062854Z",
25
+ "uuid": "1bd2e743-8681-4079-a557-6a66a8d16386",
26
+ "name": "Name of S5062854Z",
27
+ "isSingPassHolder": true,
28
+ "uen": "123456789B"
29
+ },
30
+ {
31
+ "nric": "T0066846F",
32
+ "uuid": "14f7ee8f-9e64-4170-a529-e55ca7578e2b",
33
+ "name": "Name of T0066846F",
34
+ "isSingPassHolder": true,
35
+ "uen": "123456789B"
36
+ },
37
+ {
38
+ "nric": "F9477325W",
39
+ "uuid": "2135fe5c-d07b-49d3-b960-aabb0ff2e05a",
40
+ "name": "Name of F9477325W",
41
+ "isSingPassHolder": false,
42
+ "uen": "123456789B"
43
+ },
44
+ {
45
+ "nric": "S3000024B",
46
+ "uuid": "b5630beb-e3ee-4a31-aec5-534cdc087fd8",
47
+ "name": "Name of S3000024B",
48
+ "isSingPassHolder": true,
49
+ "uen": "123456789C"
50
+ },
51
+ {
52
+ "nric": "S6005040F",
53
+ "uuid": "6c6745d9-e6c5-40ee-8c96-5d737ddbc5e4",
54
+ "name": "Name of S6005040F",
55
+ "isSingPassHolder": true,
56
+ "uen": "123456789C"
57
+ }
58
+ ]
@@ -0,0 +1,52 @@
1
+ [
2
+ { "nric": "S8979373D", "uuid": "a9865837-7bd7-46ac-bef4-42a76a946424" },
3
+ { "nric": "S8116474F", "uuid": "f4b70aea-d639-4b79-b8d9-8ace5875f6b1" },
4
+ { "nric": "S8723211E", "uuid": "178478de-fed7-4c03-a75e-e68c44d0d5f0" },
5
+ { "nric": "S5062854Z", "uuid": "1bd2e743-8681-4079-a557-6a66a8d16386" },
6
+ { "nric": "T0066846F", "uuid": "14f7ee8f-9e64-4170-a529-e55ca7578e2b" },
7
+ { "nric": "F9477325W", "uuid": "2135fe5c-d07b-49d3-b960-aabb0ff2e05a" },
8
+ { "nric": "S3000024B", "uuid": "b5630beb-e3ee-4a31-aec5-534cdc087fd8" },
9
+ { "nric": "S6005040F", "uuid": "6c6745d9-e6c5-40ee-8c96-5d737ddbc5e4" },
10
+ { "nric": "S6005041D", "uuid": "bd3fd1e0-c807-4b07-bbe4-b567cab54b8c" },
11
+ { "nric": "S6005042B", "uuid": "2dd788c0-d11f-4d5b-99af-b89d2389b474" },
12
+ { "nric": "S6005043J", "uuid": "eb196477-36b3-4c0f-ae5e-2172e2f6a6d8" },
13
+ { "nric": "S6005044I", "uuid": "843ebc6b-1de1-4d46-b1dd-9ad4aeac3a27" },
14
+ { "nric": "S6005045G", "uuid": "caafaedc-f369-498a-9e35-27e9cb7f0de2" },
15
+ { "nric": "S6005046E", "uuid": "f9b37d06-de3f-4c4f-8331-37a3b2ee6cb4" },
16
+ { "nric": "S6005047C", "uuid": "57620e0f-fdf9-4f3e-a8f6-f6088e151395" },
17
+ { "nric": "S6005064C", "uuid": "80952b2f-3455-4b59-b50f-39afbc418271" },
18
+ { "nric": "S6005065A", "uuid": "3af48e26-69a1-43e3-b5f2-303098ef3210" },
19
+ { "nric": "S6005066Z", "uuid": "8b2f8213-2fe9-493a-ac95-0b55e319e689" },
20
+ { "nric": "S6005037F", "uuid": "ae3d1d8c-6d14-449e-8ed1-9ce3d5e67607" },
21
+ { "nric": "S6005038D", "uuid": "23d3bb45-a324-46d6-b0d9-2e94194ed9ae" },
22
+ { "nric": "S6005039B", "uuid": "9ac807a2-5217-417a-a8d1-d7018b002b3f" },
23
+ { "nric": "G1612357P", "uuid": "eb125a02-3137-486f-9262-eab3e0c57a5f" },
24
+ { "nric": "G1612358M", "uuid": "d821900c-663d-4552-a753-a2e1cf8d124f" },
25
+ { "nric": "F1612359P", "uuid": "08df8d35-600c-45fd-a812-b37a27b7856a" },
26
+ { "nric": "F1612360U", "uuid": "1e90b698-23af-4acb-9fb4-eb5a80f444b6" },
27
+ { "nric": "F1612361R", "uuid": "bc134ee1-f104-4b26-9839-32047fecb963" },
28
+ { "nric": "F1612362P", "uuid": "285e8366-f3bd-48b4-8153-b47260fc9f56" },
29
+ { "nric": "F1612363M", "uuid": "379bc106-d3db-492c-a38e-fd27642ef47f" },
30
+ { "nric": "F1612364K", "uuid": "108fa3ff-c85c-461e-ba1f-8edef62b68e2" },
31
+ { "nric": "F1612365W", "uuid": "1275ae4e-02d2-4b09-9573-36ac610ede89" },
32
+ { "nric": "F1612366T", "uuid": "23c6a3a4-d9d8-445f-a588-9d91831980a6" },
33
+ { "nric": "F1612367Q", "uuid": "0c400961-eb00-425a-8df4-6656b0b9245a" },
34
+ { "nric": "F1612358R", "uuid": "45669f5c-e9ac-43c6-bcd2-9c3757f1fa1c" },
35
+ { "nric": "F1612354N", "uuid": "c38ddb2d-9e5d-45c2-bb70-8ccb54fc8320" },
36
+ { "nric": "F1612357U", "uuid": "f904a2b1-4b61-47e2-bdad-e2d606325e20" },
37
+ {
38
+ "nric": "Y4581892I",
39
+ "uuid": "acf8edda-bfdf-45fc-b140-a6ec6955d857",
40
+ "sfa": { "fid": "G730Z-H5P96", "coi": "DE", "RP": "CORPPASS" }
41
+ },
42
+ {
43
+ "nric": "Y7654321K",
44
+ "uuid": "9916f054-488e-4894-8299-412e46d89e67",
45
+ "sfa": { "fid": "123456789", "coi": "CN", "RP": "IRAS" }
46
+ },
47
+ {
48
+ "nric": "Y1234567P",
49
+ "uuid": "0fdcc18f-840b-4b35-80ee-44094a6cc66f",
50
+ "sfa": { "fid": "G730Z-H5P96", "coi": "MY", "RP": "CORPPASS" }
51
+ }
52
+ ]