Verifiable Credentials Issuance

Issue Verifiable Credentials using OpenID4VC

On this page

An organization issues Verifiable Credentials to assert information about users that will be trusted by other parties. Issuers are commonly governments or other official organizations that own user related data, such as a health or educational authority. Many other use cases are possible. For example, businesses could design scenarios for issuing verifiable credentials for customer users, in a way that benefits both customers and business partners.

A verifiable credential is a machine-verifiable identity document containing asserted claims from the issuer. The user requests a verifiable credential by interacting with an issuing organization's software, then stores the credential in a digital wallet. At a later time, the user can present the verifiable credential to an application from a verifying organization that trusts the issuer. The user should be in control of the personal data revealed to each verifier.

Verifying organizations receive credentials as part of security related application flows, such as during user registration or authentication. Thus, when the verifier considers the issuer a trusted authority, credentials provide a strong proof of identity. The verifying application then processes the claims without delay, and can integrate these trusted user attributes into its business processes.

OpenID for Verifiable Credentials

Many issuing organizations have an existing security architecture based on OAuth and OpenID Connect. Therefore, using OpenID for Verifiable Credentials (OpenID4VC) to issue verifiable credentials is typically the most convenient option. Lower level security is then outsourced to specialized components.

When using OpenID for Verifiable Credential Issuance (OpenID4VCI), a wallet interacts with two distinct services. Verifiable credentials are downloaded from a credential issuance system. This is a specialist resource server, which requires an access token with permissions to get verifiable credentials of a particular type. To get such an access token, the wallet interacts with an authorization server, which can, when required, involve additional systems.

Abstract Issuance Flow

Both systems must trust the wallet, and the credential issuance system must trust the authorization server, from which it gets access tokens. In the authorization server, one way to trust the wallet is to configure it as an OAuth client, but other options for establishing trust, such as Dynamic Client Registration, are also possible.

This article provides a simplified overview of the key behaviors an organization should understand, when issuing verifiable credentials in an OAuth context. The OpenID4VC specifications are very detailed, and cover many additional use cases. Multiple data formats and cryptographic options are supported, to provide an extensible ecosystem. For further information from the definitive guide, see the OpenID for Verifiable Credential Issuance specification.

Credential Type Design

First, the claims for a verifiable credential must be designed. In some use cases, multiple issuing organizations may need to issue the same type of verifiable credential, designed by an authority. Alternatively, the issuer may be free to design their own verifiable credentials. Ultimately these are types, containing values issued as claims.

The following snippet shows an example decoded verifiable credential claimset for a membership use case. An airline is acting as the issuer, and publishes claims related to the user's membership. The user would save the credential in a wallet and later present it to applications from verifying organizations. These verifiers could include business partners of the airline, such as airport lounges or shops.

"@context": [
"id": "",
"type": [
"issuer": "",
"validFrom": "2023-11-01T00:00:00Z",
"validUntil": "2024-02-01T00:00:00Z",
"credentialSubject": {
"id": "did:example:6828e4302b9e11eebe560242ac120002",
"membership": {
"level": "gold",
"id": "80192",

When the wallet requests a credential, it can create a cryptographic keypair that the credential issuer binds the verifiable credential to. This example credential contains a Decentralized Identifier (DID) within the credentialSubject, as a pseudonymous user identifier. Further, this example uses the W3C Verifiable Credentials Data Model. Verifiable credentials and decentralized identifiers are independent specifications, but they work well together.

Credential Metadata

The credential issuance system publishes details of the credential types it issues, in a credential issuer metadata JSON document. This document is hosted at an endpoint with a location of /.well-known/openid-credential-issuer under the system's base URL. Wallets connect to this endpoint to discover information about the issuer organization.

The wallet retrieves information about credentials supported, and downloads information that can be displayed to the user, including descriptive names and logos. The wallet also receives a list of supported authorization servers, and can download authorization server metadata at /.well-known/oauth-authorization-server. The wallet will call the authorization server's token endpoint to get an access token, then download verifiable credentials from the credential endpoint.

"credential_issuer": "",
"credential_endpoint": "",
"authorization_servers": [ "" ],
"display": [{"name": "Example Airline Credential Issuer", "locale": "en"}],
"credentials_supported": {
"MembershipCredential": {
"format": "jwt_vc_json",
"scope": "membership_credential",
"cryptographic_binding_methods_supported": ["did:ebsi", "did:key"],
"type": ["VerifiableCredential", "MembershipCredential"],
"level": {"mandatory": true, "display": [{"name": "Membership Level", "locale":"en"}, ...]},
"id": {"mandatory": false, "display": [{"name": "Membership ID", "locale": "en"}, ...]}
"proof_types_supported": ["jwt"],
"display": [{"name": "Membership", "locale": "en"} ...],

Wallet Initiated Flow

The simplest way for a user to download a verifiable credential is to start from the wallet application. For example, a wallet initiated flow can be triggered when a user interacts with a verifier application, which requests a verifiable credential of a particular type, that does not yet exist in the user's wallet. The user then runs the wallet to download one from an issuer, before continuing with the verifier application.

The wallet can query a verifiable data registry, such as a trusted database, to get a list of issuers. The wallet can inspect metadata from each issuer and present a list of issuers that support a particular credential type. A user can also view which credentials are supported by a particular issuer. The flow begins when the user chooses to download a particular verifiable credential.

The wallet then runs a code flow using the system browser, to get an access token. When the wallet sends the authorization request, it requests an access token with the specific type of the verifiable credential that will be issued, which is membership_credential in this example:

scope=openid membership_credential&

Once the wallet has an access token, it downloads a verifiable credential from the credential issuance system. A typical wallet initiated flow is illustrated here:

Wallet Initiated Flow

Issuer Initiated Flow

Issuers can provide their own user experience for downloading verifiable credentials, such as screens in web or mobile applications. The user must be authenticated in the issuer application, and can then select a verifiable credential to download, after providing any required input. The issuer application must then transfer control to the wallet, supplying the wallet with the data it needs to securely download the verifiable credential.

To run the wallet on the same device as the issuer application, the user selects an option in the issuer application that invokes a deep link. Alternatively the user can run the wallet on a different device, by opening the wallet application there and scanning a QR code rendered by the issuer application.

The data in the deep link URL or QR code contains a credential offer. This data can be provided by value or by reference, where the wallet is given a generated URL to download it. The data informs the wallet who the issuer is, which verifiable credential type to download, and how to get an access token. The following credential offer uses a grant type of authorization_code, to instruct the wallet to use the code flow to get an access token from the authorization server:

"credential_issuer": "",
"credentials": [
"grants": {
"authorization_code": {
"issuer_state": "eyJhbGciOiJSU0Et...FYUaBy"

Often though, the user is already authenticated in the issuer application, so authenticating again in the wallet would be a suboptimal user experience. To address this issue, the credential offer can use the grant type pre-authorized_code. With that grant type, the wallet can get an access token automatically.

"credential_issuer": "",
"credentials": [
"grants": {
"urn:ietf:params:oauth:grant-type:pre-authorized_code": {
"pre-authorized_code": "adhjhdjajkdkhjhdj",
"user_pin_required": true

A pre-authorized code is a short-lived, one-time value that is safe to send to another application. As an additional line of defense, the user receives a separate transaction code on another channel, such as an SMS message. The user must enter the transaction code in the wallet when confirming the download of the verifiable credential. The following diagram illustrates a typical workflow when the wallet downloads a verifiable credential using the pre-authorized code flow.

Pre Authorized Flow

How the authorization server issues the pre-authorized code, in steps 2 and 3, is implementation specific. A solution could be implemented based on a standard such as Token Exchange, to swap the access token from the user's authenticated session in the issuer application for the pre-authorized code.

Credentials and Presentations

Once the wallet has an access token with the correct permissions, it sends the token to the credential endpoint of the credential issuance system. The wallet may also add a cryptographic proof in the credential request. An example proof is a JWT signed with a private key, where that JWT provides a mechanism for retrieving the corresponding public key. The credential issuance system verifies the proof before issuing the verifiable credential. An example structure, for a verifiable credential issued as a JWT, is shown here, where the DID cryptographically binds the credential to the user.

Verifiable Credential JWT

When the verifiable credential is sent to a verifying application, the wallet encloses it within a structure called a verifiable presentation. If the verifiable credential is cryptographically bound to a public key, then the user must provide a proof-of-possession of the corresponding private key when presenting the credential. An example structure, for a verifiable presentation issued as a JWT, is shown here.

Verifiable Presentation JWT

In this example, a verifying application first validates the signature of the verifiable credential, retrieving the issuer public key from the verifiable data registry. Next, the user public key is derived from the credential, e.g. by resolving the user's DID, then the public key is used to verify the user level signature. This proof of possession mechanism ensures that no malicious party can use a verifiable credential, if, for example, one is captured in a network trace.

User Data Disclosure

When issuing verifiable credentials, a key design consideration is data minimization. A user who presents a credential to a verifying application must have control over which attributes are revealed to the verifier. To help enable this, some claims within a verifiable credential can be marked as optional in the credential issuer metadata. A related technique is atomization, to split claims across multiple, smaller, verifiable credentials. Wallets should enable user to combine verifiable credentials, from different issuers if required, into the same verifiable presentation.

Selective disclosure is another pattern, to allow users to disclose only a subset of claims from the veriable credential. The credential issuance system can issue a verifiable credential as a Selective Disclosure JWT. The verifiable credential is then issued as an SD-JWT, where claims are issued with hashed values. The wallet also receives the underlying claim values in the credential response. The wallet then builds a verifiable presentation containing both the SD-JWT and the claim values the user has chosen to disclose. The verifying application then checks the integrity of each claim value received, by rehashing and comparing to the issuer's value.

User Privacy

Some types of verifiable credentials could be trusted by many verifying organizations. This opens up the potential for unwelcome user tracking in various ways. This can include tracking the user by the credential identifier, a user identifier such as a DID, the issuer signature, or a claim such as a membership ID.


In some cases, business flows may need to share user identifiers, in which case credential issuance systems can make user identifiers an explicit part of the verifiable credential. Otherwise, it is recommended to minimize the scope for user tracking. The Verifiable Credentials Implementation Guidelines document provides further information on privacy-preserving best practices, which the wallet and credential issuance system can follow.

Business Integration

When issuing verifiable credentials for organizational use cases, some up-front design thinking is required. A technical implementation can be relatively straightforward when using a wallet and backend components with support for the required standards.

In the example use case, the user could present the verifiable credential at any verifying organization that is part of the airline's membership scheme. Threats related to fraudulent memberships are greatly reduced, due to the use of trusted identity data and strong security. When the verifiable credential is used, the verifying organization would trust the membership and provide real-time benefits to the member, such as discounts on purchases.

In some cases a verifying organization may not need to know who the user is. Receiving just the membership level claim could be sufficient for a verifier to perform work such as calculating the correct discount. Any costs might be reconciled with the airline at a later time. Since the verifying organization avoids capturing personal information about users, its regulatory footprint would likely be reduced.


This article provided an overview of the main behaviors when issuing verifiable credentials. The ability to quickly communicate strong proofs of identity from issuers to verifiers has great potential to transform many business processes. It also provides users with immediate access, and best control over how their personal data is exposed.

The Curity Identity Server can perform the role of an authorization server and can also act as a credential issuance system when required. To get started designing end-to-end flows that issue verifiable credentials, see these tutorials:

Join our Newsletter

Get the latest on identity management, API Security and authentication straight to your inbox.

Start Free Trial

Try the Curity Identity Server for Free. Get up and running in 10 minutes.

Start Free Trial