Reusable identity without a wallet application

Overview

Users are often asked to perform duplicative identity checks when doing business with an organization. Instead of asking repeatedly for the same evidence, it is better to issue a credential that can be verified the next time the user's identity data is required. However, most users will not have an identity wallet application already provisioned. The Truvera Cloud Wallet allows your platform to store credentials on behalf of your users and help your users to access them when needed.

This guide walks through a simple example of provisioning a wallet for credential storage and integrating it in issuer and verifier services. It achieves this using the following Truvera products:

The flow has three actors: Issuer (e.g., a bank), Holder (user's cloud wallet), and Verifier (e.g., a financial exchange). For simplicity, this example combines these roles by allowing the issuer and verifier to have access to the holder's wallet access key. It also uses the OpenID4VCs protocol which many developers are already familiar with. Once you understand the example, you should review the next steps for guidance on a production architecture.

Example flow

1. SETUP   
- Create Issuer DID and Verifier DID in Truvera workspace   
- Create a Proof Template with ZK predicates (e.g., age >= 18)   
- Add Issuer DID to template's trusted issuers
2. ISSUANCE (Bank/Issuer side)
    POST /openid/issuers  --> get issuerId   
    POST /openid/credential-offers --> get offerUrl   
    wallet.addCredential(offerUrl) --> credential stored in EDV
3. VERIFICATION (Exchange/Verifier side)
    POST /proof-templates/{id}/request --> get proofRequestId + qr URL   
    wallet.submitPresentation({ proofRequestUrl: qr }) --> ZKP submitted
    GET /proof-requests/{id}  (poll) --> verified: true

Prerequisites

You'll need these items from the Truvera Workspacearrow-up-right:

Secret
Purpose
Where used

TRUVERA_API_KEY

REST API authentication

Issuer / Verifier service

TRUVERA_API_URL

Base URL for REST API (e.g., https://api-testnet.dock.io)

Issuer / Verifier service

TRUVERA_ISSUER_DID

DID for signing credentials during issuance

Issuer service

TRUVERA_VERIFIER_DID

DID for creating proof requests during verification

Verifier service

You also need a Schema and a Proof Template configured in the Truvera workspace with your Issuer DID added as a trusted issuer.

To create the cloud wallet, you will also need to request a key from Truvera Support ([email protected]):

Secret
Purpose
Where used

TRUVERA_EDV_AUTH_KEY

Encrypted Data Vault access for cloud wallets

Wallet service backend


Example

1. Wallet SDK - client side

Install

Initialize a new wallet

Tip: Wallet initialization can intermittently fail with "Vault indices does not exist" errors. Use a retry loop (3 attempts, 1s delay).

Restore an existing wallet

Import a credential (OID4VC)

List credentials

Delete a credential

Submit a zero-knowledge presentation

Important: The attributesToReveal must match the input_descriptors in your proof template. The proofRequestUrl must be the qr field returned by the API, not a manually constructed URL.

2. Truvera REST API - server side

All API calls use dual-header authentication:

2a. Issue a credential

Step 1: Create an OpenID Issuer

Response: { "id": "<issuer-id>", ... }

Critical: Use algorithm: "dockbbs" for BBS+ signatures. This is required for ZK proof generation.

Step 2: Generate an OID4VC offer

Response: { "url": "openid-credential-offer://...", "id": "..." }

The url is what you pass to wallet.addCredential().

2b. Create a proof request

Response:

The qr field is the URL you pass to wallet.submitPresentation().

Important: The Issuer DID must be added to the proof template's "trusted issuers" list in the Truvera workspace. Otherwise, proof generation will silently fail.

2c. Poll for verification result

Response:

Poll this endpoint (e.g., every 3 seconds) until verified === true. Use exponential backoff for network resilience.


Next Steps

Once you understand the above example, you should separate the wallet into a privacy-by-design user-controlled web application. The issuer and verifier should not have direct access to the key for the user's wallet. Instead, we recommend the following flow.

When a user is onboarding,

  1. The user will complete identity proofing as required by existing policies,

  2. Then the issuer service calls the client wallet service to provision a cloud wallet on behalf of the user,

  3. That service assists the user in defining their key as required for your use case (using a biometric, passkey, or other login method),

  4. The wallet service then returns to the issuer the DID of the new wallet,

  5. The issuer service can then call the REST API to issue credentials with the attributes that were established during identity proofing. These credentials can be issued directly into the user's wallet using the DIDComm protocol.

When a user later needs to provide those credentials,

  1. The verifier service calls the REST API to create a proof request for the needed data,

  2. The verifier service directs the user to the client wallet service with the proof request URL,

  3. The wallet server helps the user to generate their access key using the same method as during onboarding, or a recovery method,

  4. The user can then approve the sharing of the credentials to fulfill the proof request,

  5. And the data is returned to the verifier.

Last updated

Was this helpful?