The Civic Canister is a component of a decentralized application deployed on the Internet Computer Protocol (ICP) blockchain by Civic. It is designed to handle secure storage and retrieval of credentials under Internet Identity, the authentication service for the Internet Computer. Internet Identity provides different, unlinkable identities for each app a user logs in to.
Civic (or other issuers) can issue credentials for the user as part of its identity verification flow. 3rd parties integrating Civic Pass on ICP can request these credentials from the Civic Canister. Through Internet Identity, the credential can be shared securely between the two dApps without linking the user's identities between the two dApps.
As you can see in the diagram, the user has two "versions" of their Internet Identity, Identity A and Identity B. Identity A is the one used in the Civic Canister while Identity B is the one used by the 3rd party dApp (Relying Party). When the credential data is shared between the two dApps, the two identities are not linked to each other, thanks to the attribute sharing of Internet Identity which the Civic Canister implements.
This repository contains the code to demo the above flow. civic_canister_backend
contains the code for the Civic Canister, relying_canister_frontend
contains the code for the example 3rd party, and civic_canister_frontend
contains the code for an example frontend through which credentials can be issued to the canister. See CI Build and Test (Local Setup) for instructions how to run the demo locally.
The credentials issued by the Civic Canister adhere to the W3C Verifiable Credentials specification, ensuring compatibility and interoperability with various systems and platforms.
Here is an example of a credential the Civic Canister can issue:
{
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://www.w3.org/ns/credentials/examples/v2"
],
"id": "urn:uuid:6a9c92a9-2530-4e2b-9776-530467e9bbe0",
"type": ["VerifiableCredential", "CivicPass"],
"issuer": "did:icp:v0:tglqb-kbqlj-to66e-3w5sg-kkz32-c6ffi-nsnta-vj2gf-vdcc5-5rzjk-jae",
"expiry": "2024-04-04T00:00:00Z",
"credentialSubject": {
"id": "did:icp:user-principal",
"passType": "uniqobk8oGh4XBLMqM68K8M2zNu3CdYX7q5go7whQiv",
"status": "ACTIVE",
"expirationDate": "2024-12-31T23:59:59Z"
}
}
This section provides steps to set up and run the project locally. Follow the steps below to configure your environment, build the project, and run tests.
-
Clone the repository:
git clone https://github.com/civicteam/civic-icp-canister.git cd civic-icp-canister
-
Install DFX: Follow the official DFX installation guide here.
-
Install Rust: Follow the official Rust installation guide here.
-
Install Node.js dependencies:
npm install
-
Install Rust target and dependencies:
rustup target add wasm32-unknown-unknown cargo install ic-wasm
To simplify the deployment of the canisters we provide a script deploy-civic.sh
you can find under scripts
. To execute it make sure that you have run npm install
beforehand inside the project.
./scripts/deploy-civic.sh local
Steps for the manual deployment:
-
Create canisters and start the local Internet Computer replica:
dfx start --clean --background dfx canister create --all
-
Set environment variables:
First set
export VITE_ENV="development"
Run the
scripts/set-env-vars.sh
script to set the environment variables for local deployment:source scripts/set-env-vars.sh
-
Deploy the Civic Canister and Internet Identity:
./scripts/deploy-civic.sh dfx deploy internet_identity
-
Deploy the Civic Frontend Canister:
Note: If it fails to deploy, try to deploy the RP canister first and then go back to the Civic Frontend Canister. (If you start with the RP first and it fails, try to deploy the Civic Frontend Canister and then go back to the RP.)
dfx deploy civic_canister_frontend
-
Deploy the Relying Party (RP) canister:
dfx deploy relying_canister_frontend
To run the tests ensure the test state machine binary is executable first:
chmod +x ic-test-state-machine
cargo test --test integration_tests
The following script is located in src/civic_frontend_canister
. It demonstrates how to store and fetch credentials from the Civic Canister backend. The script uses environment variables to configure the canister ID and other settings.
This script performs the following tasks:
- Load Environment Variables: Uses the
dotenv
package to load environment variables from.env.local
. - Configure Canister IDs: Reads the canister IDs from the environment variables.
- Dummy Credential Data: Sets up dummy credential data for testing purposes.
- Store Credential: Stores a credential in the Civic Canister backend.
- Fetch Credentials: Fetches and logs all credentials associated with a specified principal.
-
Ensure Environment Variables are Set: Make sure the
.env.local
file contains the necessary environment variables. -
Run the Script: Navigate to the directory containing the script and run it using Node.js:
cd src/civic_canister_frontend npm run issue-credential
- Ensure you have the required binaries in the
ic-test-machine-binaries
directory. - Modify the setup and deployment scripts as needed to suit your project's requirements.
This section describes the steps to deploy the Civic frontend, relying and backend canisters on the Internet Computer (IC) network.
- Ensure you can deploy locally.
- Ensure you have an ICP wallet to add cycles.
- Create a new identity for secure mainnet operations.
Create and use a new identity for secure operations on the mainnet.
Check your wallet balance and add cycles if necessary.
dfx wallet --network ic balance
dfx identity get-wallet
Use an external ICP wallet or exchange to transfer cycles to your wallet address. For example, to add 10 trillion cycles:
# Transfer ICP equivalent to 10 trillion cycles to your wallet address obtained from `dfx identity get-wallet`.
You can use the deploy script to deploy the canisters to mainnet in one step. Be sure that you have deployed locally first (see), this is necessary for it to work.
Ensure you have run npm install
in your project folder. Deploy locally with
./scripts/deploy-civic.sh local
Afterwards you can deploy to mainnet with
./scripts/deploy-civic.sh ic
Alternatively you can deploy manually with the following steps:
Verify if the canister IDs were already created by running
dfx canister id civic_canister_backend --network ic
dfx canister id civic_canister_frontend --network ic
dfx canister id relying_canister_frontend --network ic
If this prints the IDs for for all three canisters, then they were already created. If not run
dfx canister --network ic create --all
Export the IDs so that the frontend canisters are configured correctly for production.
export VITE_ENV="production"
source scripts/set-env-vars.sh
If it fails to deploy, try to deploy the RP canister first and then go back to the Civic Frontend Canister. (If you start with the RP first and it fails, try to deploy the Civic Frontend Canister and then go back to the RP.)
dfx canister --network ic deposit-cycles 1000000000000 civic_canister_frontend
Adjust the number of cycles as needed.
dfx deploy civic_canister_frontend --network ic --identity mainnet_identity
Follow the sames steps that you followed when deploying the frontend canister
dfx canister --network ic deposit-cycles 1000000000000 civic_canister_backend
Adjust the number of cycles as needed.
To deploy run
DFX_NETWORK=ic ./scripts/deploy-civic.sh
To upgrade run
DFX_NETWORK=ic ./scripts/upgrade-civic.sh
The Civic Canister supports stable storage and the credential data and configuration (including whitelisted issuers) will be restored when the canister is upgraded. To upgrade the canister run
DFX_NETWORK=network ./scripts/upgrade-civic.sh
setting network to ic
or local
. This also allows you to test the stable storage without having to change the canister code.