This repository contains an example of issuing vaccination certificates using Indy.
This example consists of three agents. A web agent is for an issuer who issues vaccination certificates. It shows step by step guides what to be done in Indy to issue credentials. Two mobile agents are android app and iOS app that receive vaccination certificates and present proofs of vaccination.
The agents do not use Aries frameworks. They use Indy SDK to handle certificates and proofs. They use QR codes to initiate communication and use HTTP as a communication channel. (A production service should use HTTPS instead of HTTP.)
The agents use BCovrin test network for Indy ledger.
It can be changed easily by replacing pool_transactions_genesis
file in the web
folder.
The mobile agent does not use the pool. It gets schema, credential definition, and revocation states from the web agents when it constructs proofs.
run_web.sh
runs the web agent with Docker if you have Docker Desktop.
You can also run the web agent without Docker by cd web; npm install; npm start
.
You need Nodejs and Indy SDK installed on your desktop.
Be aware that installing Indy SDK on macOS is tricky.
You can use the web agent by visiting http://localhost:3000.
You need Android Studio and an android device to run the android agent. You cannot use android simulator to run the mobile agent bacause it needs qrcode scanner and it does not contain libraries for the simulator. The android device should use WIFI on the same network as the web agent. Or the mobile agent will not be able to connect to the web agent.
You need XCode and an iOS15 device to run the iOS agent. You also need cocoapods and cmake installed. Run pod install
and open xcworkspace file.
Web agent is a web app:
- written in javascript with NodeJS
- use Express web framework
- use Vue.js frontend framework
- use Bootstrap CSS framework
- use Libindy wrapper for NodeJS
Web agent works as follows:
- creates a wallet named
demoWallet
and a pool nameddemoPool
on startup. demoWallet is created at~/.indy_client/wallet/demoWallet
and demoPool is created at~/.indy_client/pool/demoPool
using genesis file atweb/pool_transactions_genesis
. - gets it's IP address from the env variable
SERVER
or from theen0
interface - tells it's IP to the mobile agent via qrcode
- creates a DID with seed given by you. You have to register this DID to the ledger. This DID is used to create a schema and a credential definition. Schema is defined in
web/routes/schema.js
. - stores it's status, did, schema, and credential definition in a file
db.json
. You can reset the web agent by removing db.json file and demoWallet folder. You need to delete demoPool folder if you want to change the pool.
Web agent provides the following REST APIs for mobile agent:
GET /credential/credOffer/{credId}
: get the credential offerPOST /credential/credRequest/{credId}
: request the credentialPOST /credential/revoke/{credRevId}
: revoke the credentialPOST /credential/proof/{proofId}
: present a proofGET /schema
: get the schemaGET /definition
: get the credential definitionGET /revStates/{credRevId}
: get the revocation state
Android agent is an android app:
- written in kotlin
- use ML Kit's barcode scanning API
- use Libindy wrapper for Java
Android agent works as follows:
- sets env variable
EXTERNAL_STORAGE
toapplicationContext.filesDir
telling where to create wallet files. - creates a wallet named
demoWallet
and open it. - creates a master secret in the wallet and save the secret's ID in the
SharedPreference
. - most of the logics are implemented in
WalletMainActivity.kt
. It scans the qrcode, parse it, and decide whether to get a credential or to present a proof. - does not connect to the pool. The prover usually fetchs schema, credential definition, and revocation state from the ledger to create a proof. Which schema to fetch depends on the proof request. In this example, we use only one schema and one credential definition, so the Android agent simply gets them from the web agent.
Notes on the libraries and dependencies:
- Libindy wrapper for Java contains JNA which does not support android. Exclude the JNA and import the proper version that support android.
implementation ('org.hyperledger:indy:1.14.2') {
exclude group: 'net.java.dev.jna', module: 'jna'
}
implementation 'net.java.dev.jna:jna:5.8.0@aar'
- Libindy wrapper for Java does not contain native libraries.
libindy.so
andlibc++_shared.so
should be located in thewallet-app/app/src/main/jniLibs/{abi}
folder. You can findlibc++_shared.so
file in the NDK files if you install NDK.
iOS agent is an iOS app:
- written in Swift5 with SwiftUI
- use mercari/QRScanner
- use Libindy wrapper for iOS
iOS agent works as follows:
- doesn't need to set env variable
EXTERNAL_STORAGE
. Wallet files are created in the app's default document directory. - creates a wallet named
demoWallet
and open it. - creates a master secret in the wallet and save the secret's ID in the
UserDefaults
. - most of the logics are implemented in
RequestHandler.swift
. It processes getting a credential and presenting a proof. - like Android agent, does not connect to the pool.
Notes on the Libindy wrapper for iOS:
- libindy-objc podspec has some issues, so I created a new podspec Indy. The PR is not merged yet and this sample app uses my fork repo https://github.com/conanoc/indy-sdk.git
- Indy podspec depends on libzmq pod and libzmq pod uses cmake to install libzmq. So you need cmake installed on your mac.
The QR codes generated by the web agent are json data with two types:
Credential Offer
{
"type": "cred_offer",
"title": "Vaccination certificate",
"to": "Alice",
"offer_id": "abcdefg1234",
"server": "10.1.1.20:3000"
}
Proof Request
{
"type": "cred_verify",
"title": "Request proof of vaccination",
"server": "10.1.1.20:3000",
"proof_request": <json object>,
"proof_id": "abcdefg5678"
}