For the complete documentation index, see llms.txt. This page is also available as Markdown.

Creating DIDs and Registering Issuer & Verifier

What We Are Doing:

  • Creating a decentralized identifier (DID) for the Issuer and one for the Verifier.

  • Registering an Issuer bound to its DID so it can issue Verifiable Credentials.

  • Registering a Verifier bound to its DID so it can request and check credential presentations.

Why: Every credential the Issuer signs and every authorization request the Verifier sends is anchored to a DID — a portable, cryptographically verifiable identity. A wallet that receives a credential resolves the Issuer's DID to fetch the public key that proves the credential is authentic; a wallet that responds to a presentation request resolves the Verifier's DID to confirm who is asking. Creating these identities is a one-time setup step that you complete before defining schemas or issuing anything.

The service creates two DID methods: did:key (a self-contained identifier where the public key is encoded directly in the identifier) and did:web (an identifier whose DID document the service hosts for you over HTTPS). It serves the did:web documents itself — you never register or anchor a DID on any external system.

Set up your environment first. The Agent/DID, Issuer, and Verifier registration endpoints live under /agent and require a valid OIDC Bearer token carrying the admin role. This tutorial keeps a separate base URL for the Issuer and the Verifier so each call clearly targets the right service. In the current One-Click setup both point at the same deployment (one service hosts the Issuer, Verifier, and Holder APIs), though a Verifier can run under its own host in other setups — so the two variables stay distinct:

ISSUER_BASE_URL=https://your-issuer.evdi.app       # your Issuer deployment
VERIFIER_BASE_URL=https://your-deployment.evdi.app # same deployment today; may be a separate host
TOKEN=<your OIDC access token>                     # JWT with the admin role

These are the same base URLs you prepared in your .env during Project Setup. TOKEN here is the admin OIDC access token — the same value the deploy pages store per service as ISSUER_ACCESS_TOKEN / VERIFIER_ACCESS_TOKEN. The upcoming Deploying the Issuer and Deploying the Verifier pages show where each value comes from in the One-Click portal.

Local development: with AUTH_DISABLED=true you can omit the Authorization header — see Authenticating to the API.

Step 1 — Create a DID

You can create either a did:key or a did:web. A did:key requires no configuration and is ideal for getting started; a did:web produces a human-readable identifier tied to your domain whose document is resolvable at a stable HTTPS URL.

Option A — Create a did:key

POST /agent/did/key

This request takes no body and returns the new DID:

Response Body

  • did — the new did:key identifier (an Ed25519 key encoded directly in the DID).

  • verificationMethodIds — the verification method identifiers you can reference for signing and assertions.

Option B — Create a did:web

POST /agent/did/web

Request Body

  • domain (required) — the hostname that will host the DID document (for example, issuer.example.com, optionally with a port like issuer.example.com:8080). This must be a valid hostname, not a full URL.

Response Body

  • did — the created identifier, in the form did:web:<domain>:<uuid>. The service generates the trailing UUID for you.

  • didDocument — the full DID document the service will host. It uses an Ed25519 verification key (Ed25519VerificationKey2018) whose public material is published as publicKeyBase58; the same key id is referenced from both authentication and assertionMethod.

The service hosts this did:web document for you. It is served, unauthenticated, at a URL derived from the DID's UUID:

The same document is also available at https://issuer.example.com/0c8f3a52-9b2e-4d31-8a7c-1f6b9e4d2a10/.well-known/did.json. When a wallet or another service resolves your did:web, this is the document it reads to obtain your public key — so no extra publishing step is required on your side.

Save the returned did. You will pass it when registering the Issuer (or Verifier) in the next steps, and it becomes the :issuerDid path segment used throughout the Issuer API.

Step 2 — Register the Issuer

A DID on its own is just an identity. To start issuing credentials you register an Issuer bound to a DID you created in Step 1. The Issuer signs every credential with that DID's key and advertises the credentials it supports through its OpenID4VCI metadata.

POST /agent/issuer

Request Body

  • did (required) — the DID the Issuer is bound to. It must be a DID this service already created (from Step 1).

Response Body

  • issuerId — the Issuer's identifier, equal to the DID you bound it to. This is the :issuerDid path segment you'll use when assigning schemas, creating credential offers, and signing credentials.

  • credentialConfigurationsSupported — the credential configurations this Issuer can issue. It is built from the platform's active schemas — empty on a fresh deployment — and is refreshed when you create and assign schemas. Each schema and format combination becomes a credential configuration id of the form Name@Version:format, such as [email protected]:sd-jwt.

The response can also carry optional display metadata (human-readable details wallets can show) when present on the issuer record.

You can fetch the Issuer record at any time with GET /agent/issuer/:did, list every registered Issuer with GET /agent/issuers, and retrieve its OpenID4VCI metadata document with GET /agent/issuer/:did/.well-known/did-configuration.

Step 3 — Register the Verifier

The verification side follows the same pattern, but runs against your Verifier ($VERIFIER_BASE_URL) — which in the current One-Click setup shares the Issuer's deployment, though it may run under its own host in other setups, with its own DIDs and admin access token. Create a DID for the Verifier there (repeat Step 1 against $VERIFIER_BASE_URL — a separate did:key or did:web is fine) and register a Verifier bound to it. The Verifier signs the authorization requests it sends to wallets with this DID, so holders can confirm who is asking for a presentation.

POST /agent/verifier

Request Body

  • verifierId (optional) — the Verifier's DID. If you omit it, the service generates an identifier for you; pass the DID you just created so the Verifier signs its requests with that key.

Response Body

  • verifierId — the Verifier's identifier. Keep it: it is the :verifierId path segment you'll use when creating authorization requests later in the tutorial (Deploying the Verifier stores it in your .env as VERIFIER_ID).

You can list every registered Verifier with GET /agent/verifiers.

What you have now

You now have two cryptographic identities and the services bound to them:

  • An Issuer bound to its DID, ready to have schemas assigned and to issue credentials.

  • A Verifier bound to its DID, ready to request and check presentations.

If you created did:web identifiers, their documents are already live at /<uuid>/did.json on their respective domains, so any wallet can resolve them without further setup. Next, we'll finish setting up the Issuer deployment itself — saving its base URL and admin access token into our project's .env.

Last updated