Guide: Use ZK Passport to verify citizenship off-chain
Before getting started with implementing the citizenship check, let’s quickly review all the steps of the process on the diagram below.
Basically, it goes likes this:
- User installs the RariMe App and scans the passport
- Scan a QR-code in the DApp
- Gets prompted to generate a proof of eligibility in RariMe App
- The app submits the proof to the callback URL(specified in the QR code) for verification
- DApp backend fetches the verification status and citizenship data from a REST API
You can check out this flow in the sandbox: ZK Passport Demo
Pre-requisites
You can use this public instance of verifier-svc
for testing: https://api.app.rarime.com/
To get started, you SHOULD deploy your own instance of https://github.com/rarimo/verificator-svc. This service encapsulates proof verification and provides a convenient REST API for requesting parameters for the QR code, checking the user verification status, etc. You need to trust the instance of verifier-svc
so the best option is to host your own instance.
API docs: verificator-svc | ReDoc
Step #1: Ask the user to install RariMe App and scan the passport
Links for installation:
Step #2: Render a QR code with a verification request in your app
To request data for the QR code, you need to call this endpoint on the verifier-svc
:
https://rarimo.github.io/verificator-svc/#tag/Light-User-verification/operation/getVerificationLink
The following JS snippet gets data for a QR code for a passport verification with a uniqueness check on:
const verificatorUrl = 'https://api.app.rarime.com/' // your verificator-svc instance URL
const body = {
data: {
type: "user",
// Some public and unique Icebreaker user ID
// Will be used to fetch status later
id: "some-user-id",
attributes: {
// Denotes the application and activity that is requesting the verification
event_id: "icebreaker_citizenship_verification",
// Let a single passport pass verification just once
uniqueness: true
}
}
}
const response = await fetch(
`${verificatorUrl}/integrations/verificator-svc/light/private/verification-link`,
{
headers: {
'Accept': 'application/vnd.api+json',
'Content-Type': 'application/vnd.api+json',
},
method: "POST",
body: JSON.stringify(body),
}
)
const { data } = await response.json()
// Proof Params URL for RariMe app
const proofParamsUrl = data.attributes.get_proof_params
const encodedUrl = encodeURIComponent(proofParamsUrl)
// Render this data in a QR code:
const qrCodeContent = `rarime://external?type=light-verification&proof_params_url=${encodedUrl}`)
const verificatorUrl = 'https://api.app.rarime.com/' // your verifier-svc instance URL
const body = {
data: {
type: "user",
// Some public and unique Icebreaker user ID
// Will be used to fetch status later
id: "some-user-id",
attributes: {
// Denotes the application and activity that is requesting the verification
event_id: "icebreaker_citizenship_verification",
// Let a single passport pass verification just once
uniqueness: true
}
}
}
const response = await fetch(
`${verificatorUrl}/integrations/verificator-svc/light/private/verification-link`,
{
headers: {
'Accept': 'application/vnd.api+json',
'Content-Type': 'application/vnd.api+json',
},
method: "POST",
body: JSON.stringify(body),
}
)
const { data } = await response.json()
// Proof Params URL for RariMe app
const proofParamsUrl = data.attributes.get_proof_params
const encodedUrl = encodeURIComponent(proofParamsUrl)
// Render this data in a QR code:
const qrCodeContent = `rarime://external?type=light-verification&proof_params_url=${encodedUrl}`)
Some notes:
event_id
is an arbitrary string that denotes the application scope of the proof, should be something likeAPP_ID:ACTION_ID
id
is a public unique ID associated with a user within your system. It will be used in Step #3 to check the user status
After scanning the QR code, the user will complete the verification in RariMe App.
Step #3: Check the user status
You can fetch the verification status for a particular id
from this endpoint:
https://rarimo.github.io/verificator-svc/#tag/Light-User-verification/operation/getUserStatus
Here is a JS snippet for doing this
const backendUrl = 'https://api.app.rarime.com/'
const userId = 'some-user-id' // the `id` from step #2
const response = await fetch(`${backendUrl}/integrations/verification-svc/light/private/verification-status/${userId}`)
const { data } = await response.json()
// responseUserId === userId
const responseUserId = data.id
// Verification status enum:
// - "not_verified" - user is not verified
// - "verified" - user is verified
// - "failed_verification" - user verification failed
// - "uniqueness_check_failed" - user uniqueness check failed
const verificationStatus = data.attributes.status
If the user has status verified
, you can fetch the verified citizenship code like this:
const response = await fetch(`${backendUrl}/integrations/verification-svc/light/private/user/${userId}`)
const { data } = await response.json()
// ISO 3166 alpha-3 country code: https://www.iban.com/country-codes
// Note: German passports may have a single-letter "D" code
const citizenshipISOCode = data.attributes.nationality // e.g. "UKR"