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

Issuer

The Issuer Service is a foundational component of the Self-Sovereign Identity (SSI) ecosystem, enabling the creation, issuance, and management of Verifiable Credentials (VCs). A single service instance can register multiple issuers, each bound to its own DID; issuers define credential schemas, sign credentials, and hand them to interoperable wallets using the OpenID4VCI protocol over a standards-based HTTP API.

Key Highlights:

  • Standards-Based Verifiable Credentials Issues W3C-aligned credentials in two formats: SD-JWT VC (vc+sd-jwt / sd-jwt-vc), which supports selective disclosure so holders reveal only the claims a verifier needs, and JWT-VC-JSON (jwt-vc-json / jwt_vc_json). Credentials are cryptographically signed with Ed25519 (EdDSA) keys held in the service's internal key-management system.

  • Schema Management and Versioning Credential schemas are JSON-Schema templates that define the claims a credential carries, ensuring consistent credential structures. Each schema has a name (e.g. EmployeeBadge) and a string version (e.g. 1.0), and a schema together with a format yields a credential configuration id of the form Name@Version:format (e.g. [email protected]:sd-jwt). New versions can be created without disturbing existing ones, and a schema is assigned to an issuer before it can be offered.

  • OpenID4VCI Credential Offerings An issuer creates a credential offer for one or more credential configurations. The offer is returned as an openid-credential-offer:// URI and can be rendered as a QR code for the recipient to scan. Offers are claimed by a wallet through the OpenID4VCI pre-authorized code flow, with an optional PIN (transaction code) that the recipient must enter to bind the claim to a person who has the PIN.

  • Secure, Standards-Based Wallet Interactions Wallets retrieve credentials using the OpenID4VCI protocol against the issuer's published metadata, exchanging the pre-authorized code (and PIN, if required) for the signed credential. Every issuance is tracked as an issuance session so operators can observe its state.

  • Direct Credential Signing Alongside the wallet-based flow, the service exposes a direct signing endpoint that returns a signed credential in compact serialized form without a wallet round-trip — useful for server-to-server integrations and testing.

  • Architecture Overview

    • Issuer Service Instance Runs as a standalone server backed by PostgreSQL. Each issuer is registered against an existing DID and exposes its own OpenID4VCI issuer metadata. Issuers share the instance's schema store and database: a schema assigned to one issuer becomes available as credential configurations built from all active schemas.

    • Decentralized Identifiers The service creates and serves did:web documents itself over HTTPS (resolvable at /:uuid/did.json) and did:key identifiers, using Ed25519 keys (see Terminology and Concepts for how this relates to did:empe).

    • Credential Issuance and Storage Defines schemas, creates offers, signs credentials, and tracks issuance sessions.

    • Wallet Interaction Layer Implements QR code–based offers and the OpenID4VCI pre-authorized code flow (with optional PIN) for secure credential claiming.

    • Security and Access Controls All operator endpoints require a valid OIDC JWT Bearer token (Authorization: Bearer <token>), validated against a JWKS endpoint. HTTPS is required in production.


Issuing a Credential

The typical issuer workflow is: create a schema, assign it to an issuer, create an offer, then let a wallet claim it. All requests below require a valid Authorization: Bearer <token> header.

1. Create a Schema

POST /schemas

Request Body:

  • name / version: Identify the schema. Both are token-like (letters, digits, ., _, -; no spaces) and together form [email protected].

  • formats: Which credential formats this schema supports — any of sd-jwt and jwt-vc-json (defaults to both).

  • schema: A JSON-Schema describing the credential claims.

  • vct: Optional VCT identifier used for SD-JWT credential configurations.

  • jwtVcTypes: Optional credential type values used for JWT-VC-JSON configurations.

  • disclosureFrame: Optional list of claim keys that are selectively disclosable in SD-JWT.

  • defaultValues / display: Optional default claim values applied during issuance and display metadata for wallet UI.

2. Assign the Schema to an Issuer

POST /issuers/:issuerDid/schemas

Request Body:

Response Body:

3. Create a Credential Offer

POST /issuers/:issuerDid/credential-offers

Request Body:

  • credentialConfigurationIds: One or more credential configurations to offer, each of the form Name@Version:format.

  • requirePin: When true, a PIN (transaction code) is generated and must be entered by the recipient. Defaults to false.

  • issuanceMetadata: Optional per-configuration claim values applied during issuance.

Response Body:

  • credentialOfferUri: The openid-credential-offer:// URI the wallet uses to claim the credential.

  • issuanceSessionId: Identifier for tracking the issuance session.

  • credentialConfigurationIds: The credential configurations included in the offer.

  • userPin: Present only when requirePin is true.

To obtain a scannable QR code instead of JSON, call POST /issuers/:issuerDid/credential-offers/qr-code with the same body. It returns a PNG image and exposes the offer details in the X-Credential-Offer-Uri, X-Issuance-Session-Id, and (when a PIN is required) X-Pin response headers.

4. Track the Issuance Session

GET /issuance-sessions/:sessionId

Returns the session state and offer details. List all sessions for an issuer with GET /issuance-sessions?issuerId=<id>, or fetch a QR image for the session's offer URI with GET /issuance-sessions/:sessionId/qr-code.


Direct Credential Signing

For server-to-server use, a credential can be signed directly without the wallet flow.

POST /issuers/:issuerDid/credentials/sign

Request Body:

  • format: sd-jwt-vc or jwt_vc_json. This is the input value; note that the response echoes the underlying claim-format identifier, not this value (see below).

  • payload: The credential claims. For SD-JWT include a vct.

  • subjectDid: Optional DID of the credential subject.

  • disclosureFrame: SD-JWT only; lists which claims are selectively disclosable. Supplying it with jwt_vc_json is rejected.

Response Body:

The response format field reports the underlying claim-format identifier of the signed credential, which differs from the format value sent in the request. Signing with sd-jwt-vc returns "format": "dc+sd-jwt", and signing with jwt_vc_json returns "format": "jwt_vc".


Authentication

All operator endpoints are protected. Requests must include a valid OIDC-issued JWT in the Authorization header:

Tokens are validated against a JWKS endpoint (OIDC_JWKS_URL). During local development, authentication can be bypassed by setting AUTH_DISABLED=true.

Credential-offer QR code in the operator console
The generated credential-offer QR code in the operator console

Last updated