Implementation Guide on EVM
Follow these steps for a turnkey implementation of Civic Pass on EVM chains
Overview
Frontend integration using the React library to trigger pass issuance and check pass state in your app
Backend integration using the Typescript library to check for a valid Civic Pass server-side
On-Chain integration to check for a valid Civic Pass during smart contract program execution
Frontend Integration
Civic provides two React libraries to manage the issuance and status of your users' Civic Passes directly from your front-end.
The first one is a UI modal that overlays your existing UI, keeping your users within your experience. This modal will walk the user through the verification process.
The second one is an Identity Button to display user's Pass Status, ie. active, expired, revoked, and then trigger the verification process through the UI modal.
Install the React component
Install the Civic Gateway library for your chain.
Next, import and configure the GatewayProvider
component.
The GatewayProvider is a React component that enables your dApp frontend to:
access all available information of your user's Civic Pass
trigger the issuance and refresh of a new Civic Pass
The required configuration properties vary slightly depending on the chain.
Implementation
Children wrapped by this GatewayProvider
will have access to the connected wallet's Civic Pass. This is where you want to add the Identity Button and any of the gated features in your app.
We suggest placing the <GatewayProvider>
as high up in the component tree as possible, to ensure you have access to the Civic Pass state throughout your dApp.
The networkKey
is provided to you by Civic once you complete onboarding.
Configuration Parameters
The configuration parameters of the Gateway Provider vary slightly depending on the blockchain.
The React component uses ethers.js v6
Property | Description | Type |
wallet | A object containing a wallet address & an instance of an ethers v6 signer | Copy |
gatekeeperNetwork | The network key provided by Civic. |
|
Converting a viem/wagmi walletClient to an ethers v6 signer
You can convert a viem/wagmi walletClient to an ethers v6 interface by following the example of this pattern in action is available in the example repository.
Advanced Configuration
Client options
You can specify some options that affect the display behavior of the Civic modal that the user interacts with:
Property | Description | Type |
autoShowModal | Whether the Civic modal should appear automatically if the Civic Pass token state changes. | true | false |
logLevel | The log level. | debug | info | warn | error |
disableAutoRestartOnValidationFailure | [Optional] When set to true, prevents the flow to automatically restart on user validation failure (USER_INFORMATION_REJECTED). Defaults to false. | true | false |
Usage example:
Paying for your customers' transactions
If your users do not have crypto wallets, you can subsidize the cost of their passes, including the transaction cost, by signing and sending the transactions yourself.
To do this:
Set the
payer
field on the front-endCreate a back-end service to sign and send the transaction
Call that back-end service from the front-end via the
handleTransaction
callback.
Ensure you verify the source of the transaction before signing! Signing arbitrary transactions from an unsecured front-end can lead to loss of funds
For more details, see here: Docs & Sample Code
Broadcasting transactions via Civic
In the default mode of operation, the transaction required to issue or refresh the Civic Pass will be signed, but not broadcasted, by Civic. The user is responsible for broadcasting the transaction, including any fees. This flow is handled transparently by the Gateway Provider, which also communicates any fees to the user via the Civic Pass modal.
Some Passes support an alternative mode such as having the Civic backend broadcast the transaction. If the Pass Network you are using supports this, you can set the gatekeeperSendsTransaction
property to true
to turn it on.
Property | Description | Type |
gatekeeperSendsTransaction | Civic will send the transaction to the blockchain on behalf of the user. Defaults to | true | false |
forceRequireRefresh | Setting this flag forces the user to refresh their active pass when set, even if the pass is not expired. Defaults to | true | false |
Interact with a Civic Pass
You can also use the provided Identity Button reference implementation to handle everything described in this section.
Now that you have initialized the GatewayProvider context, you can use the included useGateway
hook to:
trigger the issuance of a new Civic Pass modal
access the state of the Civic Pass
Trigger the issuance of a Civic Pass
Calling the function requestGatewayToken
opens the modal dialog, which guides the user through the flow of collecting and verifying their information. The information collected varies depending on the configured Gatekeeper Network.
For example, this is the initial screen your users will see when issuing a Civic Liveness Pass:
Even if the user already has a Civic Pass, the modal supports being triggered for any possible pass status and will always display the correct screen that corresponds with that Civic Pass status.
If the the user already has a Civic Pass, triggering the modal again via requestGatewayToken
displays the following screen:
Access the status of the Civic Pass
All children of the GatewayProvider have access to the user's Civic Pass status via the useGateway function.
The gatewayStatus
indicates the overall status of the Civic Pass and should be displayed in your dApp either via custom UI or by integrating the Civic Identity Button included with the library.
The gatewayToken represents the on-chain structure of the Civic Pass. This will is only defined if the Civic Pass is ACTIVE.
If the token does not exist or is in a inactive state (e.g. frozen), this variable will be undefined
. The dApp should disable certain parts of the UI when gatewayToken is undefined
to prevent dApp usage. This only complements the on-chain check and does not replace it.
Add the Identity Button
For convenience and less code, simply drop the Identity Button widget into your UI.
It will handle both displaying the user's Civic Pass status and triggering the issuance flow for new users, all without them ever leaving your dApp.
Identity Button Specifications
The Identity button changes appearance with text and icons to indicate when the user needs to take action. It can be clicked by the user at any point in the process.
Simple Implementation
The initial click on the button by a user initiates the Civic Pass modal which will guide the user through the process of issuing their Civic Pass. If a Civic Pass already exists for the connected wallet, the UI will update to show the 'Active' status.
Once the user has gone through the issuance flow via the Civic Pass modal, any subsequent click will launch the Civic Pass iframe with a screen describing the current status of the process.
Property | Description | Values |
mode | The default setting of the button is dark. We also provide a | DARK | LIGHT |
animation | The button provides a neat animation on hover. The default value is | true | false |
Edit Pass Status UI
To expose the status of the user's Civic Pass in your UI, add the Identity Button component (also included in the Gateway library), by placing it inside the <GatewayProvider>
context you created in the previous step.
Beyond just displaying the Civic Pass status, users can also start the issuance of their Pass if they do not already have one. The Pass Status UI will update to display the correct Civic Pass status.
Civic Pass Status
Gateway Status
The gatewayStatus
indicates the overall status of the Civic Pass.
Before Issuance
Even before a Civic Pass has been issued on-chain, the Gateway Provider gives you a set of status values that you can display in our UI to keep your users informed.
Status | Description | Behavior when |
| No user wallet is connected or no gatekeeper network set. | None |
| Checking whether a Pass exists for the connected wallet. | None |
| The wallet is connected but no Pass has been requested yet. | Opens the Civic Pass modal dialog and initiates the token request flow. |
| The required user information is being collected. Depending on the Network configured, this ranges from a simple CAPTCHA to full KYC. | Opens the Civic Pass modal dialog and resumes the collection of the required information. |
| The user's identity information has been collected successfully and is being verified. This status is only available when KYC is in progress and only when the user has chosen to do KYC via on their browser. I.e. not relevant for the Ignite Pass that is used with CandyMachine v2. | Opens the Civic Pass modal dialog with a user-friendly explanation of the status. |
| The user's identity has been validated. This status is only available when KYC is in progress and only when the user has chosen to do KYC via on their browser. I.e. not relevant for the Ignite Pass that is used with CandyMachine v2. | Opens the Civic Pass modal dialog and asks the user to re-authenticate so that the request process can proceed. |
| The user's identity verification request has been rejected. This status is only available when KYC is in progress and only when the user has chosen to do KYC via on their browser. I.e. not relevant for the Ignite Pass that is used with CandyMachine v2. | Opens the Civic Pass modal displaying the reasons for the rejection. |
| The user needs to confirm wallet ownership on their wallet. | Opens the Civic Pass modal dialog with a user-friendly explanation of the status. |
| The Civic Pass has been requested and the Gatekeeper is reviewing the request. | Opens the Civic Pass modal dialog with a user-friendly explanation of the status. |
After Issuance
After a Civic has been issued on-chain, the following status values may apply.
Status | Description | Behavior when |
| The Civic Pass is Active. The user can trade. | Opens the Civic Pass modal dialog with a user-friendly explanation of the status. |
| The Civic Pass has expired. Depending on the Gatekeeper Network configured, an IP check and/or proof of wallet ownership are required to refresh it. | Proof of wallet ownership is automatically initiated. |
| The Pass has been frozen, for example because the user connected from a blocked IP. | Opens the Civic Pass modal dialog with a user-friendly explanation of the status. |
| The Pass has been revoked, for example because the user connected from a banned IP. | Opens the Civic Pass modal dialog with a user-friendly explanation of the status. |
Error Handling
Issuing a Civic Pass might fail because the user did not fulfill the constraints of the configured Gatekeeper Network or, seldomly, because of an unexpected technical error.
Status | Description | Behavior when |
| The user's location is not currently supported. | Opens the Civic Pass modal dialog with a user-friendly explanation of the status. |
| There was an unexpected error requesting a Civic Pass. | Opens the Civic Pass modal dialog and the user can restart the process. |
| The token requests has been rejected by the Gatekeeper. | Opens the Civic Pass modal dialog with a user-friendly explanation of the status. |
Civic Pass Structure
The gatewayToken represents the on-chain structure of the Civic Pass. This will only be defined if the Civic Pass is active.
Property | Description | Type |
gatekeeperNetwork | The network key against which the token was issued. | PublicKey |
issuingGatekeeper | The key of the issuing Gatekeeper. | PublicKey |
state | The on-chain token status. | State { "ACTIVE", "REVOKED", "FROZEN" } |
expiryTime | The timestamp at which the on-chain token expires. | number |
Backend Integration
While the react library is the easiest way to integrate Civic Pass on a frontend, there are many reasons why you may need to check the pass state on your backend. Here are a few ways to do this.
Using the API
Custom Pass holders can use the API to manage their passes. See here for details.
Using the Contract ABI
Overview
If you are familiar with using Ethereum libraries such as Ethers.js or Viem, you can call the blockchain directly to check the status of your pass.
The full Contract ABI is available here.
Issuing, revoking and otherwise manipulating the status of the pass is still done through the Civic Pass API and user interfaces.
This feature is available to all pass types, including both Custom and Global passes.
See here for a full working example.
Ethers.js Example
Below is an example of how to use Ethers.js to get the status of a pass.
1. Getting set up
You will need the following information to get started:
Include also whatever parts of the contract ABI you need (or import the entire file)
We are going to look up the status of a pass by wallet address, so we need the following functions:
2. Set up your Ethers provider
3. Convert the network key to a hey
The network key is a Base58-encoded string, but the contract needs it as a hex.
We can use the bs58 library to decode it.
Pass types created before July 2024 have a different mapping to slot ID - these are not supported here. If you are using a pass type created before July 2024, contact Civic support to get the associated slot ID.
4. Call the contract
Now you are ready to go - call the contract to get the status of the pass
Using the Backend Library
You can also use the NPM library to avoid having to use contract ABIs directly:
Install:
See here for a full working example
You will need the following information to get started:
The library uses Ethers for RPC calls and signing - set it up here.
Initialise the client:
The network key is a Base58-encoded string, but the contract needs it as a hex. We can use the bs58 library to decode it.
Now you are ready to make the call:
Subscribing to Events
The library also supports subscribing to events:
On-Chain Integration
Civic's on-chain integration allows developers to leverage smart contracts to verify user identities and ensure compliance with specific criteria. This section provides an overview of deploying and managing smart contracts on various chains and example use cases.
You can use Civic's provided libraries tailored to each blockchain's programming model for a straightforward integration. First, import the contract dependencies:
Inherited Smart Contract
The easiest way to integrate Civic Pass on chain is to inherit the Gated
contract, giving you access to the gated
modifier. Functions with the gated
modifier can only be called by a msg.sender that has a valid Civic Pass.
The networkKey is provided by Civic on registering for Civic Pass
Direct On-Chain Integration
If you want more control over the verification process on-chain, you can use the following code instead of the Gated contract:
User PII Retrieval
For certain Civic Pass types where the user has to supply a document or email address, such evidence items will be made available to you for approval or rejection prior to pass issuance.
As the user reaches the end of the Civic Pass data collection flow, including authorizing the collection of their PII, they will land on a screen informing them that their request is in "partner review". This serves as the interjection point where you will be able to view, inspect and decide on the outcome of the pass issuance request.
Retrieving PII Evidence
The Gatekeeper Context will communicate a new presentation request ID when the user reaches the end of the data collection flow. See here for more detail on the use of GatewayProvider
and useGateway
.
pendingRequests?.presentationRequestId
will be the identifier referred to by REQUEST_ID
in the snippets below.
High-level overview
Retrieve an access token from the Civic auth endpoint
Retrieve PII for a specific request ID from the Civic Pass Partner API
Inspect the user-provided evidence and decide it it meets the requirements
Mark the request ID as pass or fail
1. Retrieve an access token
During onboarding you will be supplied a token URL, client ID and client secret. Use these to retrieve an access token.
Request
Response
2. Retrieve PII
Use the access token from step 1 to retrieve the evidence items for a specific request.
Request
Response
3. Inspect PII evidence and decide on an outcome (only for client-owned pass networks)
In the response from 2 will be an email, data items extracted from the scanned document, as well as an array containing urls for images of the captured document front and, optionally, back. Use the URL from the array to retrieve the specific image.
Request
4. Mark the request as pass or fail (only for client-owned pass networks)
After inspecting the user-provided data and images in step 3, inform Civic that the pass should issued or rejected. Civic expects a status of either partner-pass
or partner-fail
Request
Code Examples and Demos
For practical implementation, refer to the code examples below, which demonstrate how to use Civic's libraries for EVM chains. These examples can be extended to incorporate composability with passes:
Last updated