Set up an Issuer UI API
This article details the steps to achieve full integration of the Issuer Node with the Polygon ID APIs, as well as instructs on how to set up an intuitive user interface to manage credentials.
The content of the QR code provided by the Issuer or Verifier has changed since the release 2.3.0 of the Issuer node. Instead of sending the JSON information through the QR code, now we provide an embedded link to a page where this JSON is hosted, which improves the application performance. Please check the IDEN3MESSAGE_PARSER.md file for more information on how to parse the new QR code content.
Installation
There are two options for installing and running the server alongside the UI:
For either one, you first have to clone the repository.
You can follow the instructions below or watch this video showing the same steps to set up an issuer node.
Docker Setup Guide
Running the app with Docker allows for minimal installation and a quick setup, as we have already set the infrastructure configuration (database, cache and vault storage). This is recommended for evaluation use-cases only, such as local development builds.
Docker Guide Requirements
- Unix-based operating system (e.g. Debian, Arch, Mac OS)
- Docker Engine
1.27+
- Makefile toolchain
GNU Make 3.81
There is no compatibility with Windows environments at this time.
To help expedite a lot of the Docker commands, many have been abstracted using make
commands. Included in thefollowing sections are the equivalent Docker commands that show what is being run.
Create Docker Configuration Files
Make sure you are in the root folder and then make a copy of the .env-api.sample
, .env-issuer.sample
, .env-ui.sample
environment variables files:
# FROM: ./
cp .env-api.sample .env-api;
cp .env-issuer.sample .env-issuer;
# (Optional - For issuer UI)
cp .env-ui.sample .env-ui;
.env-issuer
is used to configure the api-issuer. It contains the needed configuration to start the node such as the infrastructure configuration (postgres/redis/vault), the blockchain variables in to be able to publish the state, the basic auth variables and other variables.
.env-api
is used to configure the api-ui. This file allows the user to configure the basic auth of the api-ui, the serverURL and others.
.env-ui
is used to configure the UI with the user/password UI protection and the block explorer that will be used, among other variables.
Node Issuer Configuration
The .env-issuer
will be loaded into the Docker compose initializer.
This configuration involves 2 procedures: acquiring a blockchain URL by an RPC provider and setting up a public URL.
Acquiring a blockchain URL by an RPC provider
Any of the following RPC providers can be used:
Using Mainnet or Testnet will depend on the RPC URL you are going to use in this step. After you decide which of the RPC providers you will be using, like any of the examples above, you will need to copy the URL for the network you are willing to use.
Setting up a public URL
It is desired to run a public forwarding URL, pointing to a host, as it is going to be stored inside the credential. Localhost can't be used in this situation because the mobile app can't access it.
For testing purposes, you can use a public URL. A way to set this up is by using ngrok as a forwarding service that maps to a local port. After downloading and installing ngrok, run the following command and copy the Forwarding URL:
# For issuer-api-ui ISSUER_API_UI_SERVER_URL env var (.env-api file)
./ngrok http 3002;
Copy the Forwarding output value and paste it onto the .env-issuer
file.
# FROM: /path/to/ngrok binary
# Expected Output:
# Add OAuth and webhook security to your ngrok (its free!): https://ngrok.com/free
#
# Session Status online
# Account YourAccountUsername (Plan: Free)
# Update update available (version 3.2.1, Ctrl-U to update)
# Version 3.1.0
# Region Europe (eu)
# Latency -
# Web Interface http://127.0.0.1:4040
# Forwarding https://unique-forwading-address.eu.ngrok.io -> http://localhost:3001
#
# Connections ttl opn rt1 rt5 p50 p90
# 0 0 0.00 0.00 0.00 0.00
Configure .env-issuer
with the following details (or amend as desired).
# ...
# See Section: Getting A Public URL
ISSUER_SERVER_URL=<https://unique-forwaring-or-public-url.ngrok-free.app>
# Defaults for Basic Auth in Base64 ("user-issuer:password-issuer" = "dXNlci1pc3N1ZXI6cGFzc3dvcmQtaXNzdWVy")
# If you just want to get started, don't change these
ISSUER_API_AUTH_USER=user-issuer
ISSUER_API_AUTH_PASSWORD=password-issuer
# !!!MUST BE SET or other steps will not work
ISSUER_ETHEREUM_URL=<YOUR_RPC_PROVIDER_URI_ENDPOINT>
In case the Vault was loaded multiple times and a fresh start is needed, the following will remove remnant data:
# FROM: ./
make clean-vault;
# (Equivalent)
# rm -R infrastructure/local/.vault/data/init.out
# rm -R infrastructure/local/.vault/file/core/
# rm -R infrastructure/local/.vault/file/logical/
# rm -R infrastructure/local/.vault/file/sys/
# Expected Output/Prompt:
# rm -R infrastructure/local/.vault/data/init.out
# rm -R infrastructure/local/.vault/file/core/
# rm -R infrastructure/local/.vault/file/logical/
# rm -R infrastructure/local/.vault/file/sys/
Configure Reverse Hash
In the same environment variable file from the previous section, .env-issuer
, we also need to configure the Reverse Hash service the application will use. See below how to update each of the variables:
# Options for the RHS, respectively: On-chain, Off-chain or Centralized revocation.
ISSUER_CREDENTIAL_STATUS_RHS_MODE=< OnChain | OffChain | None>
# This one is the contract you need to provide in case you want to use on chain revocation status.
ISSUER_CREDENTIAL_STATUS_ONCHAIN_TREE_STORE_SUPPORTED_CONTRACT=<supported-onchain-revocation-contract>
# The URL where the Reverse Hash Service is hosted. Mandatory if RHS_MODE is Off-chain.
ISSUER_CREDENTIAL_STATUS_RHS_URL=http://localhost:3001
# This line should not be changed.
ISSUER_CREDENTIAL_STATUS_PUBLISHING_KEY_PATH=pbkey
# Chain ID, respectively: Mumbai or Polygon Mainnet.
ISSUER_CREDENTIAL_STATUS_RHS_CHAIN_ID=<80001 | 137>
Here you can find instructions on how to run your own Reverse Hash Service.
You can also learn more about the Reverse Hash Service modes Features section.
Start Redis, Postgres & Vault
This will start the necessary local services needed to store the wallet private key to the Hashicorp vault and allowstoring data associated to the issuer. Don't forget to initialize Docker before running this command.
# FROM: ./
make up;
# (Equivalent)
# docker compose -p issuer -f ./infrastructure/local/docker-compose-infra.yml up -d redis postgres vault;
# Expected Output:
# docker compose -p issuer -f /Users/username/path/to/sh-id-platform/infrastructure/local/docker-compose-infra.yml up-d redis postgres vault
# [+] Running 4/4
# ⠿ Network issuer-network Created 0.0s
# ⠿ Container issuer-vault-1 Started 0.5s
# ⠿ Container issuer-redis-1 Started 0.4s
# ⠿ Container issuer-postgres-1 Started
To remove all services, run the following (ignore the warnings):
# FROM: ./
make down;
# (Equivalent)
# docker compose -p issuer -f ./infrastructure/local/docker-compose-infra.yml down --remove-orphans -v;
# Expected Output:
# docker compose -p issuer -f /Users/username/path/to/sh-id-platform/infrastructure/local/docker-compose-infra.ymldown --remove-orphans
# [+] Running 4/3
# ⠿ Container issuer-postgres-1 Removed 0.2s
# ⠿ Container issuer-redis-1 Removed 0.2s
# ⠿ Container issuer-vault-1 Removed 0.2s
# ⠿ Network issuer-network Removed 0.0s
# docker compose -p issuer -f /Users/username/path/to/sh-id-platform/infrastructure/local/docker-compose.yml down--remove-orphans
# WARN[0000] The "DOCKER_FILE" variable is not set. Defaulting to a blank string.
# WARN[0000] The "DOCKER_FILE" variable is not set. Defaulting to a blank string.
# WARN[0000] The "DOCKER_FILE" variable is not set. Defaulting to a blank string.
# WARN[0000] The "DOCKER_FILE" variable is not set. Defaulting to a blank string.
Import Wallet Private Key To Vault
In order to secure the wallet private key so that the issuer can use it to issue credentials, it must be stored in the Hashicorp Vault.
Make sure the wallet that is provided has Testnet Matic to be able to send transactions and that you are providing the Private Key. Here's how you can extract the private key from MetaMask, for instance.
# FROM: ./
# Make sure to verify that the issuer-vault-1 is full initialized to avoid: "Error writing data to iden3/import/pbkey:Error making API request."
make private_key=<YOUR_WALLET_PRIVATE_KEY> add-private-key;
# (Equivalent)
# docker exec issuer-vault-1 vault write iden3/import/pbkey key_type=ethereum private_key=<YOUR_WALLET_PRIVATE_KEY>;
# Expected Output:
# docker exec issuer-vault-1 \
# vault write iden3/import/pbkey key_type=ethereum private_key=<YOUR_WALLET_PRIVATE_KEY>
# Success! Data written to: iden3/import/pbkey
Add Vault Token to Configuration File
This will get the vault token from the Hashicorp vault docker instance and add it to our ./env-issuer
file.
# FROM: ./
make add-vault-token;
# (Equivalent)
# TOKEN=$(docker logs issuer-vault-1 2>&1 | grep " .hvs" | awk '{print $2}' | tail -1);
# sed '/ISSUER_KEY_STORE_TOKEN/d' .env-issuer > .env-issuer.tmp;
# echo ISSUER_KEY_STORE_TOKEN=$TOKEN >> .env-issuer.tmp;
# mv .env-issuer.tmp .env-issuer;# Expected Output:
# sed '/ISSUER_KEY_STORE_TOKEN/d' .env-issuer > .env-issuer.tmp
# mv .env-issuer.tmp .env-issuer
Create Issuer DID
This can also be done via the UI API.
This will create a new issuer DID by creating a new Docker instance of the issuer, generating the DID of the issuer, storing it in the database, then deleting the instance.
It then copies the new DID to .env-api
.
- NON-Apple-M1/M2/Arm
- Apple-M1/M2/Arm
# FROM: ./
# NON-Apple-M1/M2/Arm Command:
make generate-issuer-did;
# (Equivalent)
# COMPOSE_DOCKER_CLI_BUILD=1 DOCKER_FILE="Dockerfile" docker compose -p issuer -f ./infrastructure/locadocker-compose.yml up -d initializer
# sleep 5
# $(eval DID = $(shell docker logs -f --tail 1 issuer-initializer-1 | grep "did"))
# @echo $(DID)
# sed '/ISSUER_API_UI_ISSUER_DID/d' .env-api > .env-api.tmp
# @echo ISSUER_API_UI_ISSUER_DID=$(DID) >> .env-api.tmp
# mv .env-api.tmp .env-api
# docker rm issuer-initializer-1
# FROM: ./
# Apple-M1/M2/Arm Command:
make generate-issuer-did-arm;
# (Equivalent)
# COMPOSE_DOCKER_CLI_BUILD=1 DOCKER_FILE="Dockerfile-arm" docker compose -p issuer -f /Users/username/path/tsh-id-platform/infrastructure/local/docker-compose.yml up -d initializer;
# sleep 5;
# DID=$(docker logs -f --tail 1 issuer-initializer-1 | grep "did");
# echo $DID;
# sed '/ISSUER_API_UI_ISSUER_DID/d' .env-api > .env-api.tmp;
# echo ISSUER_API_UI_ISSUER_DID=$DID >> .env-api.tmp;
# mv .env-api.tmp .env-api;
# docker rm issuer-initializer-1;
# Expected Output:
# COMPOSE_DOCKER_CLI_BUILD=1 DOCKER_FILE="Dockerfile-arm" docker compose -p issuer -f /Users/username/path/tsh-id-platform/infrastructure/local/docker-compose.yml up -d initializer
# WARN[0000] Found orphan containers ([issuer-vault-1 issuer-postgres-1 issuer-redis-1]) for this project. If yoremoved or renamed this service in your compose file, you can run this command with the --remove-orphans flag tclean it up.
# [+] Running 1/1
# ⠿ Container issuer-initializer-1Started 0.2s
# sleep 5
# did:polygonid:polygon:mumbai:uniqueAlphanumericKeyGenerated
# sed '/ISSUER_API_UI_ISSUER_DID/d' .env-api > .env-api.tmp
# mv .env-api.tmp .env-api
# docker rm issuer-initializer-1
# issuer-initializer-1
Configure UI
This step is required to run the separate UI application, which allows intuitive and convenient management of schemas, credentials, connections and issuer state.
Running and using the UI is optional since it implements functionalities already exposed via the UI API. It is highly recommended though, because it makes issuer management far simpler and more intuitive.
# FROM: ./
cp .env-ui.sample .env-ui;
Configure the .env-ui
file with the following details (or amend as desired):
ISSUER_UI_BLOCK_EXPLORER_URL=https://mumbai.polygonscan.com
ISSUER_UI_AUTH_USERNAME=user-ui
ISSUER_UI_AUTH_PASSWORD=password-ui
Start API UI, UI, Notifications server & Publisher
This will start the UI API that exposes endpoints to manage schemas, credentials, connections and issuer state, as wellas the UI that relies on it.
- NON-Apple-M1/M2/Arm
- Apple-M1/M2/Arm
# FROM: ./
make run-ui;
# (Equivalent)
# COMPOSE_DOCKER_CLI_BUILD=1 DOCKER_FILE="Dockerfile" docker compose -p issuer -f /Users/username/path/tsh-id-platform/local/docker-compose.yml up -d api-ui ui notifications pending_publisher;
# Expected Output:
# COMPOSE_DOCKER_CLI_BUILD=1 DOCKER_FILE="Dockerfile" docker compose -p issuer -f /Users/username/path/to/sh-id-platform/infrastructure/local/docker-compose.yml up -d api-ui ui notifications pending_publisher
# WARN[0000] Found orphan containers ([issuer-vault-1 issuer-postgres-1 issuer-redis-1]) for this project. If you removed or renamed this service in your compose file, you can run this command with the --remove-orphans flag to clean it up.
# [+] Running 4/4
# ⠿ Container issuer-ui-1 Started 0.5s
# ⠿ Container issuer-api-ui-1 Started 0.5s
# ⠿ Container issuer-notifications-1 Started 0.4s
# ⠿ Container issuer-pending_publisher-1 Running
# FROM: ./
make run-ui-arm;
# (Equivalent)
# COMPOSE_DOCKER_CLI_BUILD=1 DOCKER_FILE="Dockerfile-arm" docker compose -p issuer -f /Users/username/path/tsh-id-platform/local/docker-compose.yml up -d api-ui ui notifications pending_publisher;
# Expected Output:
# COMPOSE_DOCKER_CLI_BUILD=1 DOCKER_FILE="Dockerfile-arm" docker compose -p issuer -f /Users/username/path/to/sh-id-platform/infrastructure/local/docker-compose.yml up -d api-ui ui notifications pending_publisher
# WARN[0000] Found orphan containers ([issuer-vault-1 issuer-postgres-1 issuer-redis-1]) for this project. If you removed or renamed this service in your compose file, you can run this command with the --remove-orphans flag to clean it up.
# [+] Running 4/4
# ⠿ Container issuer-ui-1 Started 0.5s
# ⠿ Container issuer-api-ui-1 Started 0.5s
# ⠿ Container issuer-notifications-1 Started 0.4s
# ⠿ Container issuer-pending_publisher-1 Running
Now navigate to http://localhost:3002 to see the UI API's frontend:
Using the UI API
Make sure to set the HTTP authentication credentials in .env-api
to the following:
# ...
ISSUER_API_UI_AUTH_USER=user-api
ISSUER_API_UI_AUTH_PASSWORD=password-api
Then authenticate via the following form on http://localhost:3002:
This allows you to make a request via any of the endpoints using this frontend.
(Optional) Using the UI
This service is running on http://localhost:8088.
If you are using Chrome, you might get the HTTP auth modal showing and disappearing quickly. To remedy this, use the following URL: http://user-api:password-api@localhost:8088/.
File containing the basic auth credentials: .env-ui
ISSUER_UI_AUTH_USERNAME=user-ui
ISSUER_UI_AUTH_PASSWORD=password-ui
If you want to run the UI app in development mode, i.e. with HMR enabled, please follow the steps in the Development (UI) section.
Standalone Mode Guide
Running the app in standalone mode means you will need to install the binaries for the server to run natively. This is essential for production deployments.
Make sure you have Postgres, Redis and Vault properly installed & configured. Do not use make up
since those will start the containers for non-production builds, see Docker Setup Guide.
Standalone Mode Guide Requirements
- Docker Engine 1.27
- Makefile toolchain
- Unix-based operating system (e.g. Debian, Arch, Mac OS X)
- Go 1.19
- Postgres
- Redis
- Hashicorp Vault
Standalone Mode Setup
Copy
.env-api.sample
as.env-api
and.env-issuer.sample
as.env-issuer
. Please see the configuration section for more details.Run
make build-local
. This will generate a binary for each of the following commands:platform
platform_ui
migrate
pending_publisher
notifications
Run
make db/migrate
. This checks the database structure and applies any changes to the database schema.Run
./bin/platform
command to start the issuer.Run
./bin/pending_publisher
. This checks that publishing transactions to the blockchain works.Follow the steps for adding an Ethereum private key to the Vault.
Follow the steps for creating an identity as your issuer DID.
(Optional) To set up the UI with its own API, first copy
.env-ui.sample
as.env-ui
. Please see the configuration section for more details.
Development (UI)
Completing the installation process yields the UI as a minified Javascript app. Any changes to the UI source code would necessitate a full re-build to apply them. In most development scenarios this is undesirable, so the UI app can also be run in development mode like any React application to enable hot module replacement (HMR).
- Make sure that the UI API is set up and running properly (default http://localhost:3002).
- Go to the
ui/
folder. - Copy the
.env.sample
file as.env
- All variables are required to be set, with the exception of
VITE_ISSUER_LOGO
. The following are the corresponding variables present in the parent folder's.env-api
, which need to be the same. OnlyVITE_ISSUER_NAME
can differ for the UI to function in development mode.VITE_API_URL -> ISSUER_API_UI_SERVER_URL
VITE_API_USERNAME -> ISSUER_API_UI_AUTH_USER
VITE_API_PASSWORD -> ISSUER_API_UI_AUTH_PASSWORD
VITE_BLOCK_EXPLORER_URL -> ISSUER_UI_BLOCK_EXPLORER_URL
VITE_ISSUER_DID -> ISSUER_API_UI_ISSUER_DID
VITE_ISSUER_NAME -> ISSUER_API_UI_ISSUER_NAME
VITE_ISSUER_LOGO -> ISSUER_API_UI_ISSUER_LOGO
- Run
npm install
- Run
npm start
- The app will be running on http://localhost:5173.