For Authlete 2.x documentation, see 2.x version.
1. Introduction
This document explains the “OpenID for Verifiable Credential Issuance” (OID4VCI) specification and how Authlete supports the specification. This document elaborately explains overviews and details of various concepts, using well over 100 diagrams. All the explanations carefully avoid assuming prior knowledge of concepts not yet explained, allowing readers to understand the content without the need to navigate back and forth within the document. Additionally, the document refrains from delving into excessive details while presenting the overall picture to prevent readers from getting disoriented. These considerations make this document significantly more readable than the specification itself. Therefore, reading this document beforehand will be a great help when you read the specification.1.1. Specification Differences
Authlete completed its implementation of the first Implementer’s Draft of OID4VCI 1.0 (hereafter OID4VCI 1.0 ID1) in 2023. After that, the OID4VCI 1.0 specification went through the second Implementer’s Draft and was finalized in September 2025 (hereafter OID4VCI 1.0 Final). Starting from version 3.0.28, Authlete supports not only OID4VCI 1.0 ID1 but also OID4VCI 1.0 Final. However, due to the large number of breaking changes introduced between OID4VCI 1.0 ID1 and OID4VCI 1.0 Final, Authlete has adopted a different approach from the conventional method of providing configuration options for each individual specification difference. Instead, it allows switching support in bulk between OID4VCI 1.0 ID1 and OID4VCI 1.0 Final. Specifically, a property namedoid4vciVersion has been
introduced in Service, and behavior is determined based on its value. If this
property is not set or is set to 1.0-ID1, Authlete operates in compliance
with OID4VCI 1.0 ID1. On the other hand, if this property is set and its value
is 1.0 or 1.0-Final, Authlete operates in compliance with OID4VCI 1.0 Final.
In this document, notes regarding breaking changes between 1.0-ID1 and 1.0-Final
are indicated using the notation [BREAKING CHANGE].
1.2. Change History
| Revision History | |
|---|---|
| Date | Changes |
| 2023-10-22 | The initial version was published. |
| 2023-10-27 | Some subsections were added to the “OID4VCI Implementation” section. |
| 2023-11-15 | Some explanations and diagrams were updated to align with the specification changes below.
|
| 2023-11-24 | The “OID4VCI Demo” section was added. Some explanations and diagrams were updated to align with the specification change below.
|
| 2023-12-30 | A section for mdoc demo was added. Some explanations and diagrams were updated to align with the specification changes below.
|
| 2024-01-31 | Updated to align with the specification changes below.
|
| 2024-02-03 | Updated to align with the specification changes below.
|
| 2024-05-11 | Added the “POTENTIAL Interop Event / Track 1 / Light Profile” section under the “OID4VCI Demo” section. |
| 2024-06-05 | Updated the “POTENTIAL Interop Event / Track 1 / Light Profile” section to reflect a bug fix for the mdoc payload. (cf. authlete/cbor PR 10) |
| 2024-06-06 | Added the “POTENTIAL Interop Event / Track 2 / Light Profile” section under the “OID4VCI Demo” section. |
| 2024-06-11 | Updated the “4.3.2.5. Step 5 : CWT Key Proof” section to reflect a bug fix
in the format of COSE_Key. |
| 2024-06-28 | Added the “POTENTIAL Interop Event / Track 2 / Full Profile” section under the “OID4VCI Demo” section. |
| 2026-03-19 | Updated significantly to align with the completion of the OID4VCI 1.0
Final implementation. Among the many breaking changes introduced between
OID4VCI 1.0 ID1 and OID4VCI 1.0 Final, the following are particularly
impactful:
|
2. OID4VCI Specification
The OID4VCI specification defines rules for issuance of verifiable credentials.2.1. Core Technical Terms
2.1.1. Verifiable Credential
“Verifiable credential” is a key technical term in the OID4VCI specification. “Credential” in the term represents a collection of data about a user or users (or any identifiable entities). Given name, family name, and birthdate are examples of data about a user. “Verifiable” in the term indicates that it is possible to verify that the data collection has not been tampered with. Technically speaking, it means that the data collection is digitally signed.
2.1.2. Credential Issuer
Verifiable credentials are issued by a “credential issuer”. Credential issuer is also a technical term. The specification describes behaviors of a credential issuer.
2.1.3. Access Token
To obtain a verifiable credential from a credential issuer, the requester of the issuance must present an “access token” to the credential issuer. The access token here is the one defined in RFC 6749, which is the core specification of OAuth 2.0.
2.1.4. Authorization Server
Access tokens are issued by an “authorization server”. The fundamental behaviors of an authorization server are defined in RFC 6749, and there are many other standard specifications around RFC 6749 that add extra functionalities to an authorization server. The OID4VCI specification also defines additional requirements for an authorization server so that an authorization server can issue access tokens that can be used for the issuance of verifiable credentials.
2.1.5. Wallet
In the OID4VCI specification, a software application that communicates with an authorization server and a credential issuer to obtain a verifiable credential is referred to as a “wallet”. Technically speaking, within the context of issuing verifiable credentials, a wallet acts as a “client application” of OAuth 2.0. Thus, from a technical perspective, the terms wallet and client application are interchangeable in the context of the OID4VCI specification.
However, please note that in the context of “OpenID for Verifiable Presentations”, which this document does not explain, a wallet acts as a server, not as a client application.
2.1.6. Relationship
The following diagram illustrates the relationship among the core technical terms.
2.2. Access Token Issuance Overview
2.2.1. Pre-Authorized Code Flow
The specification defines multiple methods for issuing access tokens that are usable for the issuance of verifiable credentials. One of these methods is entirely new. The new one is referred to as the “pre-authorized code flow”. In the flow, as the first step, a wallet obtains a “pre-authorized code” from a credential issuer.





2.2.2. Authorization Code Flow
The other methods than the pre-authorized code flow are extensions of the traditional “authorization code flow” (RFC 6749, 4.1. Authorization Code Grant). Let’s review the flow. In the authorization code flow, as the first step, a client application (which is a wallet in the OID4VCI context) sends an “authorization request” to the “authorization endpoint” (RFC 6749, 3.1. Authorization Endpoint) of an authorization server via a web browser.






- The
issuer_staterequest parameter. - The
authorization_detailsrequest parameter. - The
scoperequest parameter.

issuer_state request parameter is a new one defined by the OID4VCI specification.
The authorization_details request parameter is defined in “RFC 9396 OAuth 2.0 Rich Authorization Requests”, a.k.a. “RAR”.
The scope request parameter is a traditional one defined in “RFC 6749 The OAuth 2.0 Authorization Framework”.
As of this writing, the OID4VCI specification does not address the cases in which the above request parameters are used in combination. It remains uncertain whether the mechanisms using these request parameters are mutually exclusive or can coexist.
Authlete’s current implementation considers all these mechanisms and generates an access token that can be used for the issuance of all the verifiable credentials requested via the request parameters.
Authlete’s current implementation considers all these mechanisms and generates an access token that can be used for the issuance of all the verifiable credentials requested via the request parameters.
2.2.3. Authorization Code Flow + issuer_state
Theissuer_state request parameter is defined in the OID4VCI specification. To use the request parameter, a wallet needs to obtain an “issuer state” from a credential issuer before making an authorization request.

issuer_state request parameter.



2.2.4. Authorization Code Flow + authorization_details
The RAR specification (RFC 9396) defines theauthorization_details parameter as a general-purpose parameter that conveys detailed information about authorization. It is up to deployments how to use the parameter.
The value of the parameter is a JSON array, and each element of the array is a JSON object. We call the object “RAR object”.

"type" property is the only mandatory property. The property indicates what the RAR object represents.
And, the OID4VCI specification defines a special value, "openid_credential", for the "type" property in order to indicate that the RAR object conveys information about the verifiable credential that the wallet wants.

2.2.5. Authorization Code Flow + scope
Thescope request parameter is one of the traditional ones defined in the core specification of OAuth 2.0 (RFC 6749). Its original usage is to list permissions that the client application wants. If the user approves the request, the authorization server issues an access token that has the requested permissions.

scope request parameter has been used for purposes beyond its original intent, and the OID4VCI specification has similarly extended the use of the scope request parameter.
A credential issuer manages the types of verifiable credentials it can issue as “credential configurations”, and publishes the list of the credential configurations at a certain place. Each credential configuration may have a "scope" property.

"scope" property in the scope request parameter to indicate which type of verifiable credentials it wants.

"scope" property.
Because the core specification of OAuth 2.0 (RFC 6749) requires that authorization servers ignore unknown
In addition, if OpenID Federation is employed, cares need to be taken to prevent metadata policies from dropping
scope values, it is likely that you need to explicitly pre-register the values of the "scope" property of the supported credentials as supported scope values with your authorization server.In addition, if OpenID Federation is employed, cares need to be taken to prevent metadata policies from dropping
scope values for verifiable credential issuance unintentionally.2.3. Credential Issuance Overview
Once a wallet obtains an access token from an authorization server, the wallet can request a credential issuer to issue a verifiable credential by presenting the access token. In the foundational procedure, the wallet sends a credential request with an access token to the credential endpoint of the credential issuer.

2.3.1. Deferred Credential Issuance
However, it is possible that the verifiable credential is not yet available when requested. For example, there might be time-consuming offline processes happening in the background. In such a case, the credential issuer issues a “transaction ID” instead.


"error":"issuance_pending"). In this case, the wallet will make a “deferred credential request” again later.
2.3.2. Batch Credential Issuance
[BREAKING CHANGE]
The batch credential endpoint has been removed in OID4VCI 1.0 Final.



2.4. Access Token Issuance Details
In the previous sections, we’ve provided an overview of access token issuance and credential issuance. In this section, we will delve into the technical details of access token issuance.2.4.1. Credential Offer
When a credential issuer issues a pre-authorized code, it provides a “credential offer” that includes the pre-authorized code instead of issuing it directly.



2.4.1.1. Credential Offer Issuance by Value
To transmit the credential offer to the wallet, a URL is employed. This URL is a “credential offer endpoint” with a query parametercredential_offer. The value of the query parameter is the content of the credential offer.

credential_offer_endpoint, which represents the wallet’s credential offer endpoint. However, especially in cases where a QR code representing the URL is used as suggested by the specification, the credential issuer do not have access to the wallet’s metadata because the credential issuer cannot know for which wallet it is going to provide a credential offer. For such cases, openid-credential-offer:// is defined as the fallback credential offer endpoint.

For the reasons mentioned above, credential issuers will implement the generation and transmission of the credential offer in their respective custom ways. Therefore, interoperability cannot be expected to a great extent.
2.4.1.2. Credential Offer Issuance by Reference
A credential offer may be passed to the wallet by reference. To be specific, the URL may contain the location of the issued credential offer instead of its content. In that case, acredential_offer_uri query parameter is used to point to the location.

credential_offer_uri query parameter points to an endpoint that returns the content of the issued credential offer.



2.4.1.3. Credential Offer Content
The actual content of a credential offer is a JSON object.
"credential_issuer" property.

"credential_configuration_ids" array.
The specific details of the array elements are discussed later.

"grants" property as a top-level property in a credential offer. The value of the "grants" property is a JSON object. The keys within the "grants" JSON object are identifiers of grant types, such as authorization_code.
The value of each entry in the "grants" JSON object is another JSON object containing properties related to the grant type represented by the corresponding key.
In the case of the issuer state, the value of the issued issuer state is placed as the value of the "issuer_state" property within the "authorization_code" JSON object, which is within the "grants" JSON object.

"pre-authorized_code" property within the "urn:ietf:params:oauth:grant-type:pre-authorized_code" JSON object, which is within the "grants" JSON object. The string "urn:ietf:params:oauth:grant-type:pre-authorized_code" here is the new identifier assigned to the pre-authorized code flow.

"urn:ietf:params:oauth:grant-type:pre-authorized_code" JSON object may contain a "tx_code" JSON object, which contains information about a “transaction code”.
When the property is provided, the token request using the pre-authorized code will have to include a transaction code. Further details about this are described later.


2.4.1.4. “credential_configuration_ids” in Credential Offer
The"credential_configuration_ids" property in a credential offer holds information
about the verifiable credentials that the credential issuer offers.
The value of the property is a JSON array. The elements in the array
are strings.
The values of the elements are the identifiers of the credential configurations.

2.4.2. Pre-Authorized Code Flow Details
Once a wallet obtains a pre-authorized code, it can make a token request with the pre-authorized code. The table below lists the request parameters required for a token request to comply with the pre-authorized code flow.
The
tx_code parameter is required if the pre-authorized code has been issued
with a tx_code object like below. In this case, it is expected that the user
will receive a transaction code corresponding to the pre-authorized code
through some out-of-band mechanism.
tx_code object may contain the following parameters to help the wallet prepare a UI component for the user to input the transaction code.
Also, additional request parameters related to client authentication may be required. For example, when the
private_key_jwt client authentication is employed, the client_assertion and client_assertion_type request parameters are required.
One ambitious attempt of the OID4VCI specification is that, depending on the configuration of the authorization server
(to be specific, when the
pre-authorized_grant_anonymous_access_supported server
metadata is true), in the pre-authorized code flow, it may be permissible to make token requests that do
not contain any information to identify the client application. If such a token request were actually made, an access
token not associated with a specific client application would be issued.c_nonce and c_nonce_expires_in response parameters,
in addition to the traditional response parameters (access_token,
token_type and expires_in) defined in the core specification of
OAuth 2.0 (RFC 6749). Further details regarding these response
parameters will be explained later.
[BREAKING CHANGE]
In OID4VCI 1.0 Final, the token response does not include
c_nonce
or c_nonce_expires_in, because c_nonce is
now issued from the newly introduced nonce endpoint.2.4.3. Issuable Credentials
While there are multiple methods available to issue access tokens for verifiable credentials, from the perspective of access token implementation, they all converge on one common goal. That is to associate information about the types of verifiable credentials that can be issued with the access token. In this document, we call such information “issuable credential”. But, please keep in mind that “issuable credential” is not an official term. Elements in the"credential_configuration_ids" array in a credential offer are JSON strings.
They indirectly specify issuable credentials by referencing credential configurations.

"credential_configuration_ids" array
in this example is one, but the array may contain multiple elements.
Such elements compose the set of issuable credentials represented by the credential offer.


issuer_state request parameter requests an access token associated with the issuable credentials specified in the credential offer that contains the issuer state.

"type":"openid_credential" may specify a credential configuration
using the "credential_configuration_id" property as the base
of an issuable credential.

openid_credential type may use the format property instead.

In a RAR object with the
openid_credential type,
the credential_configuration_id property and
the format property are mutually exclusive.[BREAKING CHANGE]
OID4VCI 1.0 Final has removed the
In OID4VCI 1.0 ID1, it was possible to request a credential that was not associated with any credential configuration. However, due to this change in the RAR object specification, as well as the change requiring that a credential request must include either the
As a result, one inconsistency inherent in the OID4VCI specification has been resolved. In OID4VCI 1.0 ID1, there were cases where a credential configuration could not be identified, despite the presence of requirements that assumed it could be identified (for example, the requirement that the
format parameter. As a result,
in OID4VCI 1.0 Final, an RAR object whose type is
openid_credential must always include
credential_configuration_id.In OID4VCI 1.0 ID1, it was possible to request a credential that was not associated with any credential configuration. However, due to this change in the RAR object specification, as well as the change requiring that a credential request must include either the
credential_configuration_id
parameter or the credential_identifier parameter, it is no
longer possible to request such credentials.As a result, one inconsistency inherent in the OID4VCI specification has been resolved. In OID4VCI 1.0 ID1, there were cases where a credential configuration could not be identified, despite the presence of requirements that assumed it could be identified (for example, the requirement that the
proof
request parameter is mandatory when proof_types_supported
is defined in the credential configuration).scope request parameter may indirectly specify one or more issuable credentials
via the "scope" property of credential configurations.




2.5. Credential Verification
In order to discuss the formats of verifiable credentials, we need to understand their intended purpose. Let’s examine the verification steps of a verifiable credential, one by one. First, the credential issuer prepares data to include in a verifiable credential. In this example, we use name, birthdate, and address.






However, from a technical perspective, it is possible for a verifiable credential and its corresponding verifiable presentation to be exactly identical.


2.5.1. Key Binding
By the way, how can a verifier confirm the following?- The verifiable presentation has been presented by the holder.
- The verifiable credential underlying the verifiable presentation has been issued by the credential issuer to the holder.



Strictly speaking, the public key used for the key binding mechanism is not always bound to the holder. Instead, it may be bound to one of the devices managed by the holder or even a device that may not be directly managed by the holder. Considering these cases, this mechanism is no longer referred to as “holder binding”.







2.6. Selective Disclosure
When presenting a verifiable presentation, the holder may choose to disclose only certain parts of the verifiable credential’s content. For example, if the verifiable credential contains name, birthdate, and address, the holder may opt to disclose only the name and birthdate while omitting the address information. We call the act of selectively disclosing chosen information like this “selective disclosure”.

- The complexity of the theory.
- The ease of implementation.
- Monetary costs for licensing.
- Legal restrictions on usage.
- Support from Hardware Security Module (HSM) products.
- How much the industry believes the algorithm is robust/secure.
Selective Disclosure for JWTs (SD-JWT) was published in November 2025 as
RFC 9901: Selective
Disclosure for JSON Web Tokens. Authlete is listed as one of the
authors of this specification.
2.6.1. SD-JWT
SD-JWT (RFC 9901) is a format that utilizes JWT (RFC 7519 JSON Web Token (JWT)) to achieve selective disclosure. The payload part of a normal JWT contains pairs of a claim name and its value.




"_sd" array, which is inserted where the original claim was located.


~), a single string is formed.




Instead of embedding the public key, a reference to it may be included.

Note that the responsibility for generating a key binding JWT lies with the holder/wallet, not the credential issuer. Therefore, even if the verifiable credential format is based on SD-JWT, the verifiable credential does not include a key binding JWT when it is issued by the credential issuer.


2.7. Verifiable Credential Formats
2.7.1. Confusion Surrounding Verifiable Credential Formats
The content of this section describes the situation as it was in 2023.
Although circumstances have since changed, it is retained as-is for
historical reference.
"typ" header parameter must be "JWT", but this requirement is not followed by w3c/vc-jose-cose. Additionally, W3C VCDM introduces the "vc" and "vp" claims as the designated places to embed verifiable credentials and verifiable presentations. However, w3c/vc-jose-cose does not utilize these "vc" and "vp" claims.
Furthermore, what adds to the confusion for newcomers is that the OID4VCI specification defines jwt_vc_json, jwt_vc_json-ld, and ldp_vc as credential format profiles based on W3C VCDM, but most people in the OpenID industry contributing to the specification do not seem inclined to support these credential format profiles. They are currently dedicating their efforts to the specification development and implementation of verifiable credential formats based on SD-JWT and “ISO/IEC 18013-5” (Personal identification - ISO-compliant driving licence - Part 5: Mobile driving licence (mDL) application).
For those discussing OAuth and OpenID Connect, ISO/IEC 18013-5 is challenging to approach because its format is based on the less familiar binary format, “Concise Binary Object Representation” (CBOR) (RFC 8949) and “CBOR Object Signing and Encryption” (COSE) (RFC 9052, RFC 9053). Additionally, detailed technical articles about it are not widely available online because ISO standards must be purchased.
The public key distribution method for verifying verifiable credentials
is also a challenging issue. When a verifier receives a verifiable
credential, they cannot determine whether it was issued according to the
OID4VCI specification. Therefore, it is not ideal to force verifiers to
search for public keys starting from the metadata of credential issuers
(/.well-known/openid-credential-issuer).
As an alternative starting point, the well-known path
/.well-known/jwt-issuer was proposed in the specification
called “SD-JWT-based Verifiable Credentials (SD-JWT VC)”.
The path name has been renamed to /.well-known/jwt-vc-issuer
later because the previous path name could easily clash with other JWT
issuer-related specifications. However, the issue remains that the path name
unnecessarily assumes that VC formats are based on JWT. Therefore, some people
are not favorable to the solution. In fact, the Italian ecosystem that
leverages OpenID Federation has opted not to use
/.well-known/jwt-vc-issuer.
Instead, they have chosen to define a new entity type identifier called
openid_credential_issuer and embed public keys for
verifiable credential verification in the
"metadata"."openid_credential_issuer"
object of the entity configuration.
As a related topic, a new client authentication
method called “OAuth 2.0 Attestation-Based Client Authentication”
is currently under development. For the method, a wallet must obtain a
“wallet attestation” from an “attester” in advance because the
wallet needs to include this attestation when performing the client
authentication method. The recipient (e.g., an authorization server)
of the attestation must obtain the public key for verifying the
attestation’s signature from the attester. Here, the distribution of
public keys for attestations is an issue similar to that described for
verifiable credentials above. And, here again,
/.well-known/jwt-vc-issuer is proposed as a
possible option. This is the very predicted concern, which makes it technically
impossible to run an attester and a credential issuer on the same server
(but whether running both on the same server is conceptually suitable or
not is a different matter). Additionally, whether the attestation format
is JWT or not is not essential.
However, a more serious issue regarding the attestation-based client
authentication is that agreement on the basic concept has not been fully
reached yet (cf. ISSUE 61).
2.7.2. Essential Functions of Verifiable Credential Formats
As mentioned in the previous section, there are many challenges related to verifiable credential formats. However, we believe that the essential functions expected from verifiable credential formats can be summarized as follows:- Verifiability
- Key Binding
- Selective Disclosure
2.7.3. SD-JWT VC
SD-JWT is a general-purpose data format and not a verifiable credential format in itself. However, by adding certain requirements, it is possible to define a verifiable credential format based on SD-JWT. “SD-JWT-based Verifiable Credentials (SD-JWT VC)” is a specification designed for this purpose. Since an overview of SD-JWT has already been provided, we will only briefly introduce the key points of SD-JWT VC in the following table. Please refer to the SD-JWT VC specification for more details.| Media Type | application/dc+sd-jwt | |||
| Issuer-signed JWT | Place | Name | Presence | Description |
| Header | alg | REQUIRED | As required by the JWT specification (RFC 7519). | |
typ | REQUIRED | dc+sd-jwt | ||
| Payload | iss | OPTIONAL | The identifier of the credential issuer. | |
iat | REQUIRED | The issuance time. | ||
nbf | OPTIONAL | The time before which the verifiable credential must not be accepted. | ||
exp | OPTIONAL | The expiry time. | ||
cnf | CONDITIONALLY REQUIRED | Required when cryptographic key binding is to be supported.
The "jwk" property representing the public key
should be included. (cf. RFC 7800) | ||
vct | REQUIRED | The identifier of the type of the verifiable credential. | ||
vct#integrity | OPTIONAL | The hash of the Type Metadata document. | ||
status | OPTIONAL | The information on how to read the status of the verifiable credential. | ||
sub | OPTIONAL | The identifier of the subject of the verifiable credential. | ||
| Key Binding JWT | Place | Name | Presence | Description |
| Header | alg | REQUIRED | As required by the JWT specification (RFC 7519). | |
typ | REQUIRED | kb+jwt (as required by the SD-JWT specification) | ||
| Payload | iat | REQUIRED | The issuance time. | |
aud | REQUIRED | The intended recipient of the key binding JWT, which is typically the verifier. | ||
nonce | REQUIRED | A string ensuring the freshness of the signature. | ||
sd_hash | REQUIRED | The base64url-encoded hash digest over the issuer-signed JWT and the selected disclosures. | ||
[BREAKING CHANGE]
The media type for SD-JWT VC was initially
The SD-JWT VC specification itself also contains the following note:
application/vc+sd-jwt.
However, despite still being under coordination, the W3C formally registered
application/vc for a different purpose (whether by mistake
or intentionally), which made it impossible to use
application/vc+sd-jwt for SD-JWT VC. As a result,
application/dc+sd-jwt came to be used instead.
This issue is mentioned on
page 51 of the OAuth WG’s
SD-JWT materials presented at IETF 121 Dublin (November 2024).The SD-JWT VC specification itself also contains the following note:
vct claim and additional claims specific to the credential type
in the issuer-signed JWT are determined by respective deployments, and they fall outside
the scope of the SD-JWT VC specification.
2.7.4. Other Verifiable Credential Formats
This document does not describe other verifiable credential formats such asjwt_vc_json.
2.8. Credential Information for Access Token
Since we have covered verifiable credential formats, we can revisit the topic of credential information for access tokens.
2.8.1. Credential Information in RAR Object
When the type of a RAR object isopenid_credential, the RAR object contains
information about an issuable credential.
Such a RAR object must include the credential_configuration_id
property when conforming to OID4VCI 1.0 Final.
When conforming to OID4VCI 1.0 ID1, it must include either the
credential_configuration_id property or the format
property. These two properties are mutually exclusive.
[BREAKING CHANGE]
OID4VCI 1.0 Final has removed the
format parameter.2.8.1.1. RAR Object with The credential_configuration_id Property
The value of the credential_configuration_id property
points to an entry in the credential configurations in the credential
issuer metadata.

mso_mdoc format uses a "claims" property.
2.8.1.2. RAR Object with The format Property
When the format property is used instead of the credential_configuration_id
property, the RAR object needs to contain complete information about an issuable credential.
The following is an excerpt from OID4VCI 1.0 ID1. As this is an older example,
please note that the value of format is vc+sd-jwt rather than dc+sd-jwt.
2.8.2. Credential Information in Credential Configuration
Information about credential configurationss is described as a part of “credential issuer metadata”. The metadata is a JSON object. It contains acredential_configurations_supported JSON object.
Each of the entries in the object represents credential configuration about a verifiable
credential supported by the credential issuer.

format property is included in all corresponding credential
objects, whereas the vct property is present only in the SD-JWT VC format.
[BREAKING CHANGE]
Breaking changes have also been made to the properties within credential
configurations. Major changes include the following:
- The introduction of the
credential_metadataobject. - The
displayproperty has been moved intocredential_metadata. - The
claimsproperty has been moved intocredential_metadata. - The type of the
claimsproperty has been changed from a JSON object to a JSON array, and the representation of claim names has been changed from JSON object keys topatharrays. - Elements in the
credential_signing_alg_values_supportedarray were previously strings regardless of the VC format, but are now defined as numeric values whenformatismso_mdoc.
2.9. Credential Issuance Details
The previous sections have covered the details about access token issuance. Next, we will delve into the details about credential issuance.2.9.1. Key Proof
As explained in the “Credential Verification” section, the wallet is expected to provide a key proof if it wishes to obtain a verifiable credential capable of key binding.
On the other hand, OID4VCI 1.0 Final removed formats other than
jwt and
introduced two new formats. As a result, the following three formats are
supported in OID4VCI 1.0 Final:
[BREAKING CHANGE]
In OID4VCI 1.0 Final, the key proof formats
ldp_vp and
cwt have been removed. Authlete implemented CWT-based key
proof and participated in the
POTENTIAL
interoperability event. However, the results of the interoperability
event revealed that improving interoperability for CWT-based key proof
would require a much more detailed specification. The
DCP WG
therefore decided that the required effort was not justified and
discontinued CWT-based key proof.2.9.1.1. Key Proof JWT
By definition, a key proof includes a public key or a reference to the key. In the case of the key proof based on JWT, several methods are employed to include this key information as listed below. A key proof JWT must use one and only one of the methods.- The
jwkheader parameter (RFC 7515, 4.1.3) - The
x5cheader parameter (RFC 7515, 4.1.6) - The
kidheader parameter (RFC 7515, 4.1.4)
You may have the impression that the combination of the
kid and
trust_chain header parameters can specify a public key for key
binding. However, the combination won’t work unless supplementary rules and
mechanisms are introduced.
jwk header parameter, the public key is embedded in the format of “JWK” (RFC 7517 JSON Web Key (JWK)).

jwk header parameter is a JSON object representing the public key.


x5c header parameter, an X.509 certificate for the public key needs to be prepared. The base64 representation of the DER representation of the certificate must be included in the x5c JSON array as the first element. If the certificate chain of the certificate is available, the chain can be included along with the certificate. See RFC 7515, 4.1.6. “x5c” (X.509 Certificate Chain) Header Parameter for the details of the format that the x5c parameter expects.

kid header parameter, its value should be a DID URL that can be resolved to the public key.


| Name | Presence | Description |
iss | CONDITIONALLY REQUIRED | The identifier of the client application (wallet). |
aud | REQUIRED | The identifier of the credential issuer. |
iat | REQUIRED | The issuance time. |
nonce | CONDITIONALLY REQUIERD | The server-provided c_nonce. |
-
The
issclaim represents the identifier of the client application (wallet) and is required in most cases. The only exception is when the access token is issued using the pre-authorized code flow, and the token request for the access token doesn’t include any information to identify the client application. Such token requests are allowed only if the authorization server permits anonymous access in the pre-authorized code flow. The authorization server’s support for this is indicated by the boolean server metadata,pre-authorized_grant_anonymous_access_supported. -
The
audclaim represents the identifier of the credential issuer and is always required. -
The
iatclaim represents the issuance time of the key proof JWT, as defined in RFC 7519, 4.1.6. “iat” (Issued At) Claim. This claim is always required. -
The
nonceclaim corresponds to thec_nonceincluded in the token response and/or the credential response. It is required when the token response contains thec_nonceparameter. Additionally, the credential issuer may mandate thenonceclaim, even when the token response doesn’t contain thec_nonceparameter. More information aboutc_noncewill be provided later.

| Key Proof JWT | Place | Name | Presence | Description |
| Header | alg | REQUIRED | As required by the JWT specification (RFC 7519). | |
typ | REQUIRED | openid4vci-proof+jwt | ||
jwk | CONDITIONALLY REQUIRED | Exactly one of these header parameters must be included, representing a public key or the reference to a public key. | ||
x5c | ||||
kid | ||||
| Payload | iss | CONDITIONALLY REQUIRED | The identifier of the client application (wallet). | |
aud | REQUIRED | The identifier of the credential issuer. | ||
iat | REQUIRED | The issuance time. | ||
nonce | CONDITIONALLY REQUIRED | The server-provided c_nonce. |
The header and payload of the key proof JWT example are decoded into the following JSONs, respectively.
2.9.1.2. Other Key Proofs
This document does not explain other key proofs. Please refer to the OID4VCI specification for them.2.9.2. c_nonce
[BREAKING CHANGE]
In OID4VCI 1.0 ID1,
c_nonce was issued by the token endpoint or
the credential endpoint. However, in OID4VCI 1.0 Final, those endpoints no
longer issue c_nonce. Instead, in OID4VCI 1.0 Final, the newly
introduced nonce endpoint issues c_nonce.2.9.2.1. c_nonce in OID4VCI 1.0 ID1
As the primary countermeasure against key proof replay, the credential issuer may require the inclusion of thenonce claim in the key proof. The value of this claim is provided as a c_nonce response parameter from the authorization server or the credential issuer.
A token response from the authorization server may include the c_nonce response parameter along with the c_nonce_expires_in response parameter, which indicates the lifetime of the c_nonce in seconds.

c_nonce response parameter as the value of the nonce claim in a key proof JWT.


nonce claim is missing, although the credential issuer requires it, or if the specified nonce value has expired, the credential endpoint will return an error response. This error response includes either the expected c_nonce value or a fresh c_nonce value. Additionally, even when a valid nonce value is provided, the credential response may still include c_nonce for future use. In either case, c_nonce is included in a credential response if the credential issuer requires key proofs include the nonce claim.

c_nonce value provided by the credential endpoint and make a credential request again with the fresh key proof.

c_nonce.

2.9.2.2. c_nonce in OID4VCI 1.0 Final
In OID4VCI 1.0 Final, the nonce for key proof is issued from the credential issuer’s “Nonce Endpoint.”
c_nonce property. The wallet uses
the value of this c_nonce property as the nonce for key proof.
2.9.2.3. Implementation of c_nonce
A closer look at the OID4VCI 1.0 ID1 specification shows that an access token is always present in contexts wherec_nonce appears. A token response is
returned when an access token is issued, and requests to the credential
endpoint include an access token.
Therefore, in OID4VCI 1.0 ID1, c_nonce can be managed in association with an
access token. If implemented this way, a separate c_nonce can be generated
for each access token, and each can have its own expiration time. As a side
effect, it also prevents a situation where different clients share and use the
same c_nonce.
On the other hand, in OID4VCI 1.0 Final (more precisely, from ID2 onward),
c_nonce cannot be managed in association with an access token. This is
because, by specification, the nonce endpoint is accessible without an access
token, meaning that no access token exists at the time the nonce endpoint
generates a c_nonce.
In the context of implementing the nonce endpoint, not only is there no access
token, but it is also impossible to identify which client application (wallet)
is making the request. Therefore, it is not possible to generate a c_nonce
per client. As a result, in OID4VCI 1.0 Final, all clients (including
attackers) share the same c_nonce.
The nonce endpoint returns the same c_nonce to any requester within the same
time window.
2.9.3. Credential Request
[BREAKING CHANGE]
The credential request specification has been changed in a breaking manner.
In OID4VCI 1.0 ID1, either the
In contrast, in OID4VCI 1.0 Final, the
In OID4VCI 1.0 ID1, either the
format parameter or the
credential_identifier parameter was required, and the
parameter used to specify key proof was proof.In contrast, in OID4VCI 1.0 Final, the
format parameter has been
removed, and either credential_identifier or the newly
introduced credential_configuration_id is required.
In addition, the parameter used to specify key proof has been changed to
proofs.A
credential_response_encryption JSON object may be present
for credential response encryption, but it is not discussed here.2.9.3.1. Credential Request in OID4VCI 1.0 ID1
2.9.3.1.1. Credential Information in Credential Request
A credential request is an HTTP POST request with an access token and a JSON-formatted payload. This payload contains credential information and may include an optional key proof.
"format" property and additional format-specific properties. For example, when the value of the "format" property is "jwt_vc_json", an accompanying "credential_definition" property is expected.

jwt_vc_json that includes the given_name, family_name and degree claims only.
However, there are the following issues here:
- It’s not easy to determine which of the issuable credentials meet the specified conditions.
- There’s a possibility that multiple issuable credentials may satisfy the conditions.
- Minor differences in conditions can lead to the selection of a different issuable credential.
- It’s not easy to confirm whether the presented access token has the permission to request verifiable credentials that meet the specified conditions.
The OID4VCI has recently introduced the
credential_identifier parameter
that is mutually exclusive with the format parameter. However, such
credential instance identifiers become available (if the credential issuer supports
the mechanism) only when RAR objects of type openid_credential are used,
and the specification says that the credential instance identifiers cannot be used
when the scope parameter is used. The credential_identifier
parameter is a solution designed solely for a specific use case and does not serve
as a resolution for the issue mentioned above.
See Issue 197
for further discussions.2.9.3.1.2. Key Proof Information in Credential Request
Key proof information in a credential request is represented by a"proof" property. The value of the property is a JSON object.

"proof" object contains a mandatory "proof_type" property that indicates the format of the key proof.
When the value of the "proof_type" property is "jwt", a JWT is used as a key proof. In this case, the "proof" object contains a "jwt" property. The value of the "jwt" property is a JWT that conforms to the specification of the key proof JWT.


2.9.3.2. Credential Request in OID4VCI 1.0 Final
2.9.3.2.1. Credential Information in Credential Request
A credential request is an HTTP POST request that includes an access token and a JSON-formatted payload. The payload contains credential information and optional key proof.
credential_configuration_id property or the
credential_identifier property. These two properties are
mutually exclusive.


credential_configuration_id property specifies a key
that exists in the credential_configurations_supported
object in the credential issuer’s metadata.
The credential_identifier property specifies a value listed
in the credential_identifiers array included in the RAR
object in the token response. For example, if the token response is the same as
the example shown in 6.2. Successful Token Response of
OID4VCI 1.0 Final (excerpted below),
CivilEngineeringDegree-2023 or
ElectricalEngineeringDegree-2023, as listed in the
credential_identifiers array, can be specified as the value
of the credential_identifier parameter.
In the OID4VCI 1.0 Final specification, if a token response includes an RAR
object (whose
type is openid_credential), that
RAR object must include a credential_identifiers array.
However, since it is possible to send a credential request using a credential
configuration ID even without credential identifiers, it would have been
preferable for the credential_identifiers array to be
optional.credential_identifiers array included in the RAR object of
a token response come from? In fact, the OID4VCI specification does not mention
this. Even when reviewing the definition of credential configurations, there is
no property corresponding to a set of supported credential identifiers.
Therefore, it is reasonable to assume that the definition of credential
identifiers is left unconstrained and can be freely determined by the
credential issuer.
That said, defining credential identifiers in an unstructured manner is
undesirable. Therefore, Authlete has decided to automatically derive credential
identifiers based on the following rules:
- If a credential configuration includes a
credential_definition.typearray, each element prefixed with"{credential configuration ID}/"is treated as a credential identifier. - If a credential configuration does not include a
credential_definition.typearray, the credential configuration ID itself is used as the sole credential identifier.
credential_definition object, and that object contains a
JSON array with the key type, whose value is
["Type1", "Type2"].
ConfigurationA/Type1
and ConfigurationA/Type2—are automatically derived.
credential_definition.type array, the derived credential
identifier is simply the credential configuration ID itself.
credential_definition.type array is formally defined
for the mso_mdoc format. On the other hand, it is not formally
defined for the dc+sd-jwt format. However, regardless of whether
it is formally defined, if the credential_definition.type
array is present, Authlete uses it to derive credential identifiers.
2.9.3.2.2. Key Proof Information in Credential Request
The key proof information in a credential request is represented by the"proofs" property. The value of this property is a JSON object.

"proofs" object represents a key proof type (see
Appendix F. Proof Types). The corresponding value is
an array, and each element in the array is a key proof.

jwt.

2.9.4. Credential Response
[BREAKING CHANGE]
The credential response specification has been changed in a breaking manner.
In OID4VCI 1.0 ID1, the value of the
If the credential issuer cannot immediately provide the requested VC, the credential response includes a
In OID4VCI 1.0 ID1, the credential response includes the
In OID4VCI 1.0 ID1, the value of the
credential parameter in the
credential response represents the issued VC. In contrast, in OID4VCI 1.0
Final, the credential parameter has been removed and replaced with
the credentials parameter. The value of this parameter is an array
containing the issued VCs. If the credential request includes key proofs, the
same number of VCs are included in the credentials array.If the credential issuer cannot immediately provide the requested VC, the credential response includes a
transaction_id parameter.
This is the same in both OID4VCI 1.0 ID1 and OID4VCI 1.0 Final; however,
OID4VCI 1.0 Final additionally introduces the interval parameter.In OID4VCI 1.0 ID1, the credential response includes the
c_nonce
parameter, but in OID4VCI 1.0 Final it does not, as c_nonce is
issued by the nonce endpoint.2.9.4.1. Credential Response in OID4VCI 1.0 ID1
2.9.4.1.1. Credential Response with Verifiable Credential
A credential response is an HTTP response containing JSON. When a verifiable credential is successfully issued, it is placed in the JSON as the value of the"credential" property.

"credential" property is a JSON string in the format of SD-JWT.

c_nonce and c_nonce_expires_in response parameters, as explained previously.


~) are used as delimiters between the components. Note that because a key binding JWT is generated by a wallet, verifiable credentials do not have a key binding JWT when they are issued by a credential issuer.

- The value of the
typheader parameter is"vc+sd-jwt". - The payload contains
"cnf"."jwk"for key binding. - The payload contains the
"_sd_alg"property, which indicates the hash algorithm used for disclosures. - The payload does not contain user claims like
"given_name". Instead, it contains the"_sd"array, which holds digest values of disclosures for user claims.


"_sd_alg" property and are listed in the "_sd" array. The order of the digest values in the array must be independent of the order of the disclosures in the SD-JWT. In this example, the digest values are listed in ASCII-code order.


2.9.4.1.2. Credential Response with Transaction ID
When the requested verifiable credential is not ready, the credential endpoint returns a transaction ID instead of a verifiable credential. The transaction ID is included in the credential response as the value of the"transaction_id" response parameter. The following is an example from the OID4VCI specification.
2.9.4.1.3. Credential Response with Error
If the credential request cannot be processed successfully, the credential endpoint will return an error response, with the type of error reflected in the value of the"error" response parameter. Below is a sample error excerpt from the specification.
nonce claim’s absence or expiration, the error code "invalid_proof" is used. Here is an example from the specification in such a case.
2.9.4.2. Credential Response in OID4VCI 1.0 Final
2.9.4.2.1. Credential Response with Verifiable Credential
A credential response is an HTTP response containing JSON. If the issuance of VCs is successful, the VCs are included in the JSON as the value of thecredentials property. Each element of the credentials
property is a JSON object, and each contains a credential property. The
value of the credential property represents each VC. The format of the
credential property depends on the format of the VC.

"credential" property is a JSON
string in SD-JWT format.
Now, let us take a closer look at the details of SD-JWT-based VCs.

~) are used as delimiters between
the components. Note that because a key binding JWT is generated by a wallet,
verifiable credentials do not have a key binding JWT when they are issued
by a credential issuer.

- The value of the
typheader parameter is"dc+sd-jwt". - The payload contains
"cnf"."jwk"for key binding. - The payload contains the
"_sd_alg"property, which indicates the hash algorithm used for disclosures. - The payload does not contain user claims like
"given_name". Instead, it contains the"_sd"array, which holds digest values of disclosures for user claims.


"_sd_alg" property and are listed in the "_sd" array.
The order of the digest values in the array must be independent of the
order of the disclosures in the SD-JWT. In this example, the digest values
are listed in ASCII-code order.


2.9.4.2.2. Credential Response with Transaction ID
When the requested verifiable credential is not ready, the credential endpoint returns a transaction ID instead of a verifiable credential. The transaction ID is included in the credential response as the value of the"transaction_id"
response parameter. The following is an example from the OID4VCI specification.
2.9.4.2.3. Credential Response with Error
If the credential request cannot be processed successfully, the credential endpoint will return an error response, with the type of error reflected in the value of the"error" response parameter. Below is a sample error
excerpt from the specification.
In OID4VCI 1.0 ID1, a credential request may include the
format
parameter. The error code unsupported_credential_format
is defined for this parameter. However, in OID4VCI 1.0 Final, the
format parameter has been removed. Accordingly, the error code
unsupported_credential_format has also been removed.2.9.5. Deferred Credential Request
The wallet can send a request to the deferred credential endpoint using a transaction ID. This request should be an HTTP POST request containing JSON with a"transaction_id" property holding the transaction ID.
2.9.6. Deferred Credential Response
[BREAKING CHANGE]
The deferred credential response specification has been changed in a breaking
manner.
In OID4VCI 1.0 ID1, the value of the
If the requested VC is still not ready, in OID4VCI 1.0 ID1 the deferred credential endpoint returns an HTTP error with the
In OID4VCI 1.0 ID1, the deferred credential response includes the
In OID4VCI 1.0 ID1, the value of the
credential parameter in a
deferred credential response represents the issued VC. In contrast, in OID4VCI
1.0 Final, the credential parameter has been removed and replaced
with the credentials parameter. The value of this parameter is an
array containing the issued VCs. In addition, the
notification_id parameter may also be included in the
response.If the requested VC is still not ready, in OID4VCI 1.0 ID1 the deferred credential endpoint returns an HTTP error with the
issuance_pending error code. In contrast, in OID4VCI 1.0
Final, it returns a 202 Accepted response containing
transaction_id and interval.In OID4VCI 1.0 ID1, the deferred credential response includes the
c_nonce parameter, but in OID4VCI 1.0 Final it does not, as
c_nonce is issued by the nonce endpoint.2.9.6.1. Deferred Credential Response in OID4VCI 1.0 ID1
The deferred credential endpoint will respond with an HTTP response containing JSON. If a verifiable credential has been issued successfully, this JSON includes the"credential" response parameter, representing the verifiable credential.
"error" parameter. Particularly, when the requested verifiable credential is not yet ready, the error code "issuance_pending" is used.
2.9.6.2. Deferred Credential Response in OID4VCI 1.0 Final
The deferred credential endpoint returns an HTTP response containing JSON. If the VCs have been successfully issued, the JSON includes a"credentials"
property. The value of the "credentials" property is a JSON array, and each
element is a JSON object. Each JSON object contains a "credential" property,
whose value represents the issued VC.
transaction_id and
interval.
2.9.7. Batch Credential Request
[BREAKING CHANGE]
The batch credential endpoint has been removed in OID4VCI 1.0 Final. The
following describes the batch credential request in OID4VCI 1.0 ID1.
"credential_requests" JSON array. The array is a list of JSON objects, each of which represents a credential request.




2.9.8. Batch Credential Response
[BREAKING CHANGE]
The batch credential endpoint has been removed in OID4VCI 1.0 Final. The
following describes the batch credential response in OID4VCI 1.0 ID1.
"credential_responses" JSON array. The array is a list of JSON objects, each of which represents a credential response. The elements in the array correspond to the elements in the "credential_requests" array in the preceding batch credential request.


c_nonce and c_nonce_expires_in as top-level properties for cases where the wallet sends a credential request or a batch credential request with a key proof in the future.


2.10. Public Key Distribution
To verify the signature of a verifiable credential or a verifiable presentation, verifiers need to obtain the public key that corresponds to the private key which the credential issuer used to sign the verifiable credential. How to distribute public keys for verifying the signatures of verifiable credentials is outside the scope of the OID4VCI specification. However, here we describe a few proposed methods.2.10.1. Embedding X.509 Certificate
One method for public key distribution is to embed an X.509 certificate for the public key within the verifiable credential. In the case of JWT-based verifiable credentials, it is likely that the"x5c" header parameter (RFC 7515, 4.1.6) will be used for that purpose.
2.10.2. Embedding within Entity Configuration
Another method utilizes the OpenID Federation specification and embeds the public key within the entity configuration of the credential issuer. The Italian ecosystem has definedopenid_credential_issuer
as a new entity type identifier, which represents a credential issuer,
and the ecosystem uses the "jwks" metadata to place the credential
issuer’s public keys within.

2.10.3. jwt-vc-issuer
Another proposal for public key distribution is/.well-known/jwt-vc-issuer.
The new well-known path is intended to serve as the starting point for searching for the public key.

"jwks_uri" property in the JSON points to the location of the JWK Set of the issuer.
Verifiers can find the target public key in the JWK Set.
The JWT VC issuer metadata may contain the
"jwks" property
rather than the "jwks_uri" property. This can happen when
the JWT VC issuer has a difficulty in providing a separate endpoint for
its JWK Set for various reasons.2.11. Specification Summary
The content of this section describes the situation as it was in 2023.
Although circumstances have since changed, it is retained as-is for
historical reference.
"type":"openid_credential", and
(4) using scope values referencing entries in the credential_configurations_supported metadata.
For credential issuance, the specification introduces three endpoints, namely, (1) the credential endpoint, (2) the batch credential endpoint, and (3) the deferred credential endpoint.
Pieces of credential information appear at some locations such as (1) the
credential_configurations_supported issuer metadata,
(2) RAR objects, (3) credential
requests, and (4) batch credential requests. Due to the lack of consistency
and identifiability among them, the specification may not fully achieve its
intended goal. However, in exchange for sacrificing full interoperability,
real-world ecosystems will be able to issue verifiable credential for their
specific needs based on the specification along with their supplementary
specifications.
The specification does not go into the specifics of verifiable credential formats,
but it does establish rules related to the jwt_vc_json, jwt_vc_json-ld,
ldp_vc, mso_mdoc, and vc+sd-jwt formats. Among them, the formats that
have recently been garnering the most attention are “SD-JWT VC” and “mdoc”
(ISO/IEC 18013-5:2021). eIDAS 2.0 mandates support for
SD-JWT-based and mdoc-based formats.
Public key distribution is also not covered in the specification. Some
recognized proposals for public key distribution include (1) embedding
an X.509 certificate in the verifiable credential itself, (2) using
"openid_credential_issuer"."jwks" in
the entity configuration of the credential issuer, and (3) using
/.well-known/jwt-vc-issuer.
While the OID4VCI specification still has room for improvements, real-world
ecosystems can leverage it for their specific needs with practical compromises
and local supplementary specifications.
3. OID4VCI Implementation
3.1. Authlete Overview
Developers can build their own credential issuers and authorization servers / OpenID providers conforming to the OID4VCI specification by utilizing Authlete. While most vendors directly provide implementations of frontend servers such as an authorization server, Authlete takes a different approach. Authlete provides a set of Web APIs with which developers themselves can implement their own frontend servers. Authlete sits behind such frontend servers and is invisible from end users.
- Any technical components of developer’s choice
- User authentication method
- User management system
- API gateway
- Programming language
- Web framework
- Cloud service
- Full control over user data
- No need to upload user data to the OAuth/OIDC vendor’s server.
- Manageable compliance with various regulations for the protection of user data.
- Full control over end-user facing frontend servers
- Corporate brand management across all aspects of UI/UX.
- Enforced proper layer separation in system design
- API authorization is separated from user management and user authentication.
- OAuth/OIDC protocol processing is separated from API gateway and frontend servers.
Architects in enterprises have begun to realize that they need full control over
user identity management and the Web APIs of their services for the success of
their business and recognize that the “OAuth/OIDC component as a Service”
approach offered by Authlete is the ideal solution. Please watch
“Security Offered as
Components Empowering Enterprises to Gain Control”, a panel discussion
on this topic held at EIC 2023.
3.2. Authlete Configuration
3.2.1. Authlete Version
OID4VCI 1.0 ID1 has been supported since the initial release of Authlete 3.0, while OID4VCI 1.0 Final has been supported since Authlete 3.0.28.
3.2.2. Authlete Server Configuration
The “Verifiable Credentials” feature must be enabled on the Authlete server. If you are using the on-premises version of Authlete, please confirm that the configuration file (authlete-server.properties) includes the
following line to enable this feature.
3.2.3. Authlete Service Configuration
| Property | Type | Description | |
verifiableCredentialsEnabled | boolean | This flag controls availability of features related to Verifiable Credentials such as support of the OID4VCI specification. | |
oid4vciVersion | string | This property indicates the version of the OpenID for Verifiable
Credential Issuance specification to be used. If the value of this
property is unset or "1.0-ID1", the service operates
according to the OID4VCI 1.0 ID1 specification. If the value is
"1.0-Final" or "1.0", the service operates
according to the OID4VCI 1.0 Final specification. | |
credentialIssuerMetadata | credentialIssuer | string | The identifier of the credential issuer when this service acts
as a credential issuer. This property corresponds to the
credential_issuer metadata defined in the OID4VCI
specification.The value must be a valid URL with the https scheme and without
the query part and the fragment part. In addition, Authlete limits the value
to ASCII only and a maximum length of 200 characters.To act as a credential issuer, this property must be set. |
authorizationServers | string array | The identifiers of the authorization servers the credential issuer
relies on for authorization when this service acts as a credential issuer.
This property corresponds to the authorization_servers
metadata defined in the OID4VCI specification.The values must be HTTP-accessible URLs. | |
credentialEndpoint | string | The URL of the credential endpoint when this service acts as a credential
issuer. This property corresponds to the credential_endpoint
metadata defined in the OID4VCI specification.The value must be a valid URL with the https scheme and without
the fragment part. In addition, Authlete limits the value to ASCII only and
a maximum length of 200 characters.To act as a credential issuer, this property must be set. | |
batchCredentialEndpoint | string | The URL of the batch credential endpoint when this service acts as a
credential issuer. This property corresponds to the
batch_credential_endpoint metadata defined in the
OID4VCI 1.0 ID1 specification.The value must be a valid URL with the https scheme and without
the fragment part. In addition, Authlete limits the value to ASCII only and
a maximum length of 200 characters.It is optional whether to implement the batch credential endpoint. Note that in OID4VCI 1.0 Final, the batch credential endpoint has been removed. | |
deferredCredentialEndpoint | string | The URL of the deferred credential endpoint when this service acts as
a credential issuer. This property corresponds to the
deferred_credential_endpoint metadata defined in the
OID4VCI specification.The value must be a valid URL with the https scheme and without
the fragment part. In addition, Authlete limits the value to ASCII only and
a maximum length of 200 characters.If the credential endpoint and/or the batch credential endpoint of your credential issuer may issue transaction IDs, you must implement the deferred credential endpoint. | |
notificationEndpoint | string | The URL of the notification endpoint when this service acts as
a credential issuer. This property corresponds to the
notification_endpoint metadata defined in the
OID4VCI specification.The value must be a valid URL with the https scheme and without
the fragment part. In addition, Authlete limits the value to ASCII only and
a maximum length of 200 characters. | |
nonceEndpoint | string | The URL of the nonce endpoint when this service acts as
a credential issuer. This property corresponds to the
nonce_endpoint metadata defined in the
OID4VCI 1.0 Final specification.The value must be a valid URL with the https scheme and without
the fragment part. In addition, Authlete limits the value to ASCII only and
a maximum length of 200 characters.According to the requirements of the OID4VCI 1.0 Final specification, if a nonce endpoint is configured, key proofs that do not include a nonce will be rejected. | |
credentialRequestEncryptionJwks | string | A JWK Set document containing the public keys for encrypting credential
requests and the private keys for decrypting encrypted credential
requests. The public portion of this property corresponds to the
credential_request_encryption.jwks metadata
defined in the OID4VCI 1.0 Final specification. | |
credentialRequestEncryptionEncValuesSupported | string array | The JWE enc algorithms supported for credential request
encryption. This property corresponds to the
credential_request_encryption.enc_values_supported
metadata defined in the OID4VCI 1.0 Final specification.The valid values are the names of JWEEnc enum entries such as "A256GCM". | |
credentialRequestEncryptionZipValuesSupported | string array | The JWE zip algorithms supported for credential request
encryption. This property corresponds to the
credential_request_encryption.zip_values_supported
metadata defined in the OID4VCI 1.0 Final specification.The valid values are the names of JWEZip enum entries such as "DEF". | |
requireCredentialEncryptionRequest | boolean | The flag indicating whether to always encrypt credential requests.
This property corresponds to the
credential_request_encryption.encryption_required
metadata defined in the OID4VCI 1.0 Final specification.If this property is set to true, all credential requests are required to be encrypted. | |
credentialResponseEncryptionAlgValuesSupported | string array | The JWE alg algorithms supported for credential response
encryption. This property corresponds to the
credential_response_encryption.alg_values_supported
metadata defined in the OID4VCI specification.The valid values are the names of JWEAlg enum entries such as "ECDH_ES".
Only asymmetric algorithms are accepted. | |
credentialResponseEncryptionEncValuesSupported | string array | The JWE enc algorithms supported for credential response
encryption. This property corresponds to the
credential_response_encryption.enc_values_supported
metadata defined in the OID4VCI specification.The valid values are the names of JWEEnc enum entries such as "A256GCM". | |
credentialResponseEncryptionZipValuesSupported | string array | The JWE zip algorithms supported for credential response
encryption. This property corresponds to the
credential_response_encryption.zip_values_supported
metadata defined in the OID4VCI 1.0 Final specification.The valid values are the names of JWEZip enum entries such as "DEF". | |
requireCredentialEncryptionResponse | boolean | The flag indicating whether to always encrypt credential responses.
This property corresponds to the
credential_response_encryption.encryption_required
metadata defined in the OID4VCI specification.If this property is set to true, every credential request is required to include the credential_response_encryption
JSON object. | |
batchSize | integer | The maximum size of the proofs array in a credential
request. This property corresponds to the
batch_credential_issuance.batch_size
metadata defined in the OID4VCI 1.0 Final specification.If the value of this property is set to 2 or greater, the /api/{service-id}/vci/metadata
API of Authlete will insert a
batch_credential_issuance object into the
generated credential issuer metadata. Within that object, the value
of the batch_size field will be set to the value
of this batchSize property. | |
display | string | A JSON array representing the display name of the credential issuer.
This property corresponds to the display metadata
defined in the OID4VCI specification. | |
credentialsSupported | string | Credentials supported by the credential issuer when this service acts as
a credential issuer. This property corresponds to the
credential_configurations_supported metadata defined
in the OID4VCI specification.The value must be a JSON object. Non-ASCII characters may be contained, but Authlete limits the maximum number of characters to 16383. To act as a credential issuer, this property must be set. For backward compatibility, the name of this property remains credentialsSupported and will not be renamed to
credentialConfigurationsSupported. | |
credentialOfferDuration | integer | The default duration of credential offers in seconds. When an API to the /vci/offer/create API does not contain
the duration request parameter or the value of the parameter
is 0 or negative, the value of this property is used as the default value.If the value of this property is 0 or negative, the default value per Authlete server is used as the default value. | |
preAuthorizedGrantAnonymousAccessSupported | boolean | This property indicates whether token requests using the pre-authorized
code flow by unidentifiable client applications are allowed. This property corresponds to the pre-authorized_grant_anonymous_access_supported
metadata defined in the OID4VCI specification. | |
cnonceDuration | integer | The duration or time window of a c_nonce, expressed in
seconds.In OID4VCI 1.0 ID1, c_nonce is issued by the token endpoint
or the credential endpoint. The value of this property is used as the
validity period of the c_nonce.In OID4VCI 1.0 Final, c_nonce is issued by a dedicated nonce
endpoint. The value of this property is used as the nonce time window.
All nonces issued within the same time window have the same value.If the value of this property is 0 or less, the default value configured on the Authlete server is used. | |
credentialTransactionDuration | integer | The default duration of transaction IDs in seconds that may be issued
as a result of a credential request or a batch credential request. If the value of this property is 0 or negative, the default value per Authlete server is used. | |
credentialDuration | integer | The default duration of verifiable credentials in seconds. Some Authlete APIs such as the /vci/single/issue API and
the /vci/batch/issue API may issue one or more verifiable
credentials. The value of this property specifies the default duration
of such verifiable credentials.The value 0 indicates that verifiable credentials will not expire. In the case, verifiable credentials will not have a property that indicates the expiration time. For example, JWT-based verifiable credentials will not contain the exp claim
(RFC 7519,
Section 4.1.4).Authlete APIs that may issue verifiable credentials recognize a request parameter that can override the duration. For example, a request to the /vci/single/issue API contains an order object
that has a credentialDuration parameter that can override
the default duration. | |
credentialJwks | string | The JWK Set document containing private keys that are used to sign
verifiable credentials. Some Authlete APIs such as the /vci/single/issue API and
the /vci/batch/issue API may issue one or more verifiable
credentials. The content of this property is referred to by such APIs.Authlete APIs that may issue verifiable credentials recognize a request parameter that can specify the key ID of a private key that should be used for signing. For example, a request to the /vci/single/issue
API contains an order object that has a
signingKeyId parameter that can specify the key
ID of a private key to be used for signing. When a key ID is not specified,
Authlete will select a private key automatically.If JWKs in the JWK Set do not contain the kid property
(RFC 7517,
Section 4.5) when this credentialJwks property
is updated, Authlete will automatically insert the kid
property into such JWKs. The JWK thumbprint
(RFC 7638)
computed with the SHA-256 hash algorithm is used as the value of the
kid property. | |
credentialJwksUri | string | The URL at which the JWK Set document of the credential issuer is exposed. This URL is used as the value of the jwks_uri property in the
JWT issuer metadata. The metadata itself is published at
/.well-known/jwt-issuer. See
SD-JWT-based Verifiable Credentials (SD-JWT VC) for details about the
JWT issuer metadata. | |
3.3. Authlete APIs
3.3.1. Overall Picture of Authlete APIs for OID4VCI
The following diagram illustrates the relationship between the endpoints of the frontend servers (the credential issuer and the authorization server) and Authlete APIs. The details of the Authlete APIs are explained in the following sections.
Although not shown in the diagram above, there is also a
/vci/nonce API for implementing the nonce endpoint defined
in the OID4VCI 1.0 Final specification.3.3.2. Authlete API Call
A significant difference between Authlete 2.x and Authlete 3.0 is how to call Authlete APIs. In Authlete 2.x and older versions, developers call Authlete APIs using a pair of an API key and an API secret (e.g., a service API key and a service API secret). In Authlete 3.0, on the other hand, developers call Authlete APIs with an access token. Developers can obtain access tokens for Authlete APIs using the new Web console, which is significantly different from the previous ones. In Authlete 2.x and older versions, there are two separate Web consoles: the service owner console (for managing services corresponding to authorization servers and OpenID providers) and the developer console (for managing client applications). In Authlete 3.0, however, a single Web console is provided, and its appearance and functionality change based to on the privileges of the presented access token.
Another difference is found in the path component of Authlete APIs. In Authlete 3.0, most Authlete APIs include a service ID as part of the path, such as
/api/{ServiceID}/auth/authorization, where {ServiceID} represents the identifier of a service (i.e., the service API key in Authlete 2.x).
In this document, as well as in other documents, the prefix
/api/{ServiceID} for API paths is omitted.authlete.properties) from:
3.4. Credential Offer Issuance
As mentioned before, the process of issuing credential offers varies among credential issuers. For example, after interacting with a user via a web browser, the credential issuer may display a QR code like below:
openid-credential-offer://?credential_offer={CredentialOffer}”
where {CredentialOffer} holds the following credential offer.
openid-credential-offer://?credential_offer_uri={CredentialOfferUri}
{CredentialOfferUri} holds a URL-encoded URL like
https%3A%2F%2Ftrial.authlete.net%2Fapi%2Foffer%2FTctoiNm9lYASTBT6XRGb8RQsrClKczCxDtqLY1jLvpk.
3.4.1. The /vci/offer/create API
Regardless, credential issuers supporting credential offers must be able to
create them. For the functionality, Authlete provides the /vci/offer/create
API. The following table summarizes the API.
| Request to the /vci/offer/create API | ||
| HTTP Method and Content-Type | GET | (query parameters) |
| POST | application/json | |
| POST | application/x-www-form-urlencoded | |
| Request Parameters | credentialConfigurationIds | A string array, which will be used as the value of
the "credential_configuration_ids" property of a credential offer.
This request parameter is mandatory. |
authorizationCodeGrantIncluded | A boolean value (true or false) indicating
whether to include the "authorization_code" object in the
"grants" object. | |
issuerStateIncluded | A boolean value (true or false) indicating
whether to include the "issuer_state" property in the
"authorization_code" object in the "grants"
object.When this parameter is true, Authlete generates an issuer
state and puts it in the "authorization_code" object as
the value of the "issuer_state" property. | |
preAuthorizedCodeGrantIncluded | A boolean value (true or false) indicating
whether to include the
"urn:ietf:params:oauth:grant-type:pre-authorized_code"
object in the "grants" object.When this parameter is true, Authlete generates a
pre-authorized code and puts it in the
"urn:ietf:params:oauth:grant-type:pre-authorized_code"
object as the value of the "pre-authorized_code" property. | |
txCode | A transaction code that should be associated with the pre-authorized code.
If this parameter is not empty, a tx_code object will be
embedded in the
"urn:ietf:params:oauth:grant-type:pre-authorized_code"
object. Consequently, the token request using the pre-authorized code
will have to include the tx_code request parameter with
the value specified by this parameter. | |
txCodeInputMode | The input mode of the transaction code. The value specified by this
parameter will be used as the value of the input_mode
property in the tx_code object.The predefined values listed in the OID4VCI specification are "numeric" and "text" only, but the
/vci/offer/create API accepts other values
for the future extension in addition to the predefined ones. | |
txCodeDescription | The description of the transaction code. The value specified by this
parameter will be used as the value of the description
property in the tx_code object. | |
subject | The subject (the unique identifier) of the user associated with
the credential offer. This parameter is mandatory. | |
duration | The duration of the credential offer in seconds. If this parameter holds a positive integer, the value is used as the duration of the credential offer being issued. Otherwise, the value of the credentialOfferDuration property of the
service is used. | |
context | The general-purpose arbitrary string associated with the credential
offer. Developers can utilize this parameter as they like. Authlete does not care about the content of this parameter. | |
properties | The extra properties associated with the credential offer, which are
general-purpose key-value pairs. The extra properties will be eventually associated with an access token which will be created based on the credential offer. | |
jwtAtClaims | The additional claims in JSON object format that are added to the payload
part of the JWT access token. This parameter has a meaning only when the format of access tokens issued by the service is JWT. In other words, it has a meaning only when the accessTokenSignAlg property of the service
holds a non-null value.The additional claims will be eventually associated with an access token which will be created based on the credential offer. | |
authTime | The time when the user authentication was performed during the course
of issuing the credential offer. The time is represented as seconds since the Unix epoch. | |
acr | The Authentication Context Class Reference of the user authentication performed during the course of issuing the credential offer. | |
/vci/offer/create API returns JSON like below.
"info" object in the API response contains information about the created
credential offer. The "credentialOffer" property in the "info" object is a
string representing the created credential offer. The value of the
"credentialOffer" property in the above example looks like the following when
formatted in a human-readable manner.
"credentialOffer" property, you can construct a URL
by concatenating the following components:
- A credential offer endpoint. For example,
openid-credential-offer://. ?credential_offer=.- URL-encoded
"credentialOffer"value.
/vci/offer/info API returns JSON like below, which is almost the same
as the response from the /vci/offer/create API.
/vci/offer/info API is to assist developers in
implementing an endpoint on their credential issuer that provides information
about a credential offer when queried by a wallet.

- A credential offer endpoint. For example,
openid-credential-offer://. ?credential_offer_uri=.- URL-encoded URL of the endpoint including the identifier of the credential offer. For example,
https://trial.authlete.net/api/offer/9gjVvas8Q5BkkrkSfZv-DbsBYJvlw6ZPMK-TeCkQDEc.
3.4.3. Credential Offer Issuance Example
The sample authorization server implementation written in Java, authlete/java-oauth-server, can function as a credential issuer. Its/api/offer/issue endpoint provides an HTML page for developers
to create custom credential offers. A java-oauth-server instance using
Authlete 3.0 is currently running at https://trial.authlete.net, and the
endpoint is active for trial purposes at https://trial.authlete.net/api/offer/issue.

inga.
3.5. Credential Endpoint Implementation
The credential endpoint can be implemented using the following Authlete APIs.
Let’s go through the processing steps within a credential endpoint implementation.
As the first step, the implementation of the credential endpoint receives
a credential request from a wallet.

/auth/introspection API.

/auth/introspection API validates the access token, and returns
information about the access token.

/vci/single/parse API.

You might wonder why the access token is sent to the
Note: The above explanation applies only to OID4VCI 1.0 ID1. In OID4VCI 1.0 Final, it is not possible, in principle, to manage
/vci/single/parse API,
even though its validation has already been completed. The reason for this is that,
in Authlete’s implementation, c_nonce is associated with an access token.
To validate the nonce claim in a key proof that may be included in the
credential request, Authlete needs to know the value of c_nonce associated
with the access token.Note: The above explanation applies only to OID4VCI 1.0 ID1. In OID4VCI 1.0 Final, it is not possible, in principle, to manage
c_nonce in
association with an access token, so the value of c_nonce is
computed independently of the access token./vci/single/parse API parses and validates the credential request, and returns the information about the credential request.


/vci/single/issue API.

The reason for sending the access token to Authlete again is the need to refresh
the
c_nonce value associated with the access token in case it has expired./vci/single/issue API issues a verifiable credential or a transaction ID
according to the credential issuance order, and prepares the content of the
credential response.

/vci/single/issue API can be used as the message body of the credential
response.



3.5.1. Credential Issuance Order
The steps to prepare a credential issuance order are as follows.3.5.1.1. Credential Issuance Order Step 1
Get the subject (= unique identifier) of the user associated with the access token from the access token information. The"subject" property in the response
from the /auth/introspection API (cf. IntrospectionResponse)
holds the value of the subject.

3.5.1.2. Credential Issuance Order Step 2
Retrieve information about the user identified by the subject from the user database.
3.5.1.3. Credential Issuance Order Step 3
Get the information about the issuable credentials associated with the access token from the access token information. The"issuableCredentials" property in
the response from the /auth/introspection API holds the information as a string.
This string needs to be parsed as a JSON array.

"issuableCredentials"
property is a JSON object containing the following keys:
3.5.1.4. Credential Issuance Order Step 4
Get the credential information included in the credential request from the credential request information. The"info" object (see.
CredentialRequestInfo) in the response from the
/vci/single/parse API (see.
CredentialSingleParseResponse) holds various
information about the credential request.

"info" object contains the following keys:
3.5.1.5. Credential Issuance Order Step 5
Confirm that the access token has the necessary permissions for the credential request by checking if the credential information is a subset of any issuable credentials.
vct determine the set of
claims and eliminate the need to specify individual claims one by one.
The proposal makes it impossible to check the access token’s
permissions only by mechanically seeing the inclusion relationship between
JSON objects.
Therefore, the confirmation of whether the access token has sufficient
permissions is left to be implemented by each credential issuer according to
their respective policies. While permission checks based on inclusion
relationships are implemented in Authlete, they have been disabled.
The
checkPermissions method of the
AbstractOrderProcessor class in
java-oauth-server
repository serves as an example implementation of permission-checking logic.3.5.1.6. Credential Issuance Order Step 6
Determine the set of user claims to embed in the VC being issued based on the credential information, and get the values of the user claims from the dataset retrieved from the user database.
3.5.1.7. Credential Issuance Order Step 7
Build a credential issuance order using the collected data.
3.5.1.8. Credential Issuance Order Step 8
Prepare a request to the/vci/single/issue API (cf. CredentialSingleIssueRequest).

| Request to the /vci/single/issue API | ||
| HTTP Method and Content-Type | POST | application/json |
| Request Parameters | accessToken | The access token presented at the credential endpoint. |
order | A credential issuance order that provides an instruction for issuing a verifiable credential or a transaction ID. | |
3.5.1.9. Credential Issuance Order Step 9
Send the prepared request to the/vci/single/issue API.

3.5.1.10. Credential Issuance Order Steps Summary
The following diagram is a summary of the steps for preparing a credential issuance order.
3.6. Batch Credential Endpoint Implementation
To be written.3.7. Configure oid4vci in the Authlete Management Console
As mentioned in 3.3.2. Authlete API Call, Authlete 3 has a single console to configure services and clients.
You can configure the Verifiable Credentials such as support of the OID4VCI specification in the Authlete Management Console.
3.7.1. Service Settings
To enableoid4vci in Authlete Service Settings:
- Log in to the Authlete Management Console
- Click on your Organization name and choose your Service.
- Navigate to Service Settings > Verifiable Credentials > General
- Under the
Verifiable Credentials Featuresection, pressEnableto turn on support for Verifiable Credentials. - Optionally, enable the
Anonymous Accessproperty if you want to allow token requests by unidentifiable client applications. - Click the
Save Changesbutton to apply the updates.
To configure oid4vci Credential Issuer Metadata Properties:
- Navigate to Service Settings > Verifiable Credentials > Credential Issuer Metadata
-
Configure the metadata properties to suit your requirements. The following properties correspond to the metadata defined in the OID4VCI specification:
- Authorization Servers
- Credential Issuer Identifier
- Credential Endpoint
- Batch Credential Endpoint
- Deferred Credential Endpoint
- Supported Credentials
- Anonymous Access
-
Click the
Save Changesbutton to apply the updates.
3.7.2. Client Settings
To configureoid4vci in Authlete Client Settings:
- Log in to the Authlete Management Console
- Click on your Organization name and choose your Service.
- Navigate to Client Settings > Verifiable Credentials > General
- Under the
Credential Response Encryptionsection, enableRequireoption to turn on support for response encryption. - Click the
Save Changesbutton to apply the updates.
4. OID4VCI Demo
[BREAKING CHANGE]
The examples in Sections 4.1 through 4.5 are based on OID4VCI 1.0 ID1. Please
note that following them exactly will not work with the current implementation.
For Authlete settings and demo procedures for OID4VCI 1.0 Final, please refer to oid4vci-final-setup.md in the oid4vci-demo repository.
For Authlete settings and demo procedures for OID4VCI 1.0 Final, please refer to oid4vci-final-setup.md in the oid4vci-demo repository.
4.1. Pre-Authorized Code Flow + Key Proof + SD-JWT VC
4.1.1. Setup
Download the resources used in this demo.4.1.2. Pre-Authorized Code
Access https://trial.authlete.net/api/offer/issue to generate a “credential offer” that contains a “pre-authorized code”.
inga and inga in the “Login ID” field and the “Password” field,
confirm that “Pre-authorized code grant included” is checked, and press
the “Submit” button. You will see a result page displayed.

pre-authorized_code
property in the JSON is the issued pre-authorized code.
Set the issued pre-authorized code to shell variable PRE_AUTHORIZED_CODE
to use it in the next step.
4.1.3. Access Token
Send a token request using the pre-authorized code flow. The client for this demo is a public client, so client authentication is not required. That is, it’s not necessary to add request parameters related to client authentication.access_token parameter and the c_nonce parameter.
Set the values of the response parameters to shell variables for later use.
4.1.4. Key Proof
Generate a “key proof JWT” using the holder keyholder.jwk and the
generate-key-proof script. The JWK file and the script are contained in the
oid4vci-demo repository.
generate-key-proof script will generate a key proof JWT like below.
Decoding the header and the payload of the key proof JWT by base64url will show the following JSONs.
generate-key-proof script can be directly set to
the shell variable KEY_PROOF_JWT by doing the following.
4.1.5. SD-JWT VC
Send a “credential request” with the generated key proof JWT to the “credential endpoint”.credential parameter in the response is the issued SD-JWT VC.
If the SD-JWT VC is set to the shell variable SD_JWT, the content of the SD-JWT VC
can be decoded by invoking the decode-sd-jwt script as follows.
4.2. Authorization Code Flow + PAR + DPoP + mdoc
4.2.1. Setup
Download the resources used in this demo.4.2.2. Request URI
Generate a “DPoP proof JWT” (RFC 9449) usingdpop.jwk, a private key for DPoP,
and the generate-dpop-proof script.
generate-dpop-proof script will generate a DPoP proof JWT like below.
Decoding the header and the payload of the DPoP proof JWT by base64url will show the following JSONs. Note that the
htu claim in the payload holds the
URL of the PAR endpoint.
DPoP header and (2) that the scope parameter contains
org.iso.18013.5.1.mDL.
scope value assumes that the credential_configurations_supported
JSON object in the credential issuer metadata contains at least one credential configuration
whose scope property holds org.iso.18013.5.1.mDL.
request_uri parameter in the response is the issued request URI.
It will be used in the next step.
4.2.3. Authorization Code
Send an authorization request to the authorization endpoint using a web browser. Don’t forget to replace$REQUEST_URI in the URL with the actual request URI
you received from the PAR endpoint in the previous step.
The authorization page will be displayed. Input
inga and inga in the
“Login ID” field and the “Password” field there, and press the “Authorize”
button.

You will be redirected to the redirection endpoint. The page displayed at this endpoint will show you the value of the issued authorization code. It will be used in the next step.

4.2.4. Access Token
Generate a DPoP proof JWT to access the token endpoint. Make sure that the argument given to the-u option of the generate-dpop-proof script is $TOKEN_ENDPOINT
(not $PAR_ENDPOINT).
htu claim in the payload should hold the
URL of the token endpoint.
AUTHORIZATION_CODE before executing the following command.
access_token parameter. Please set the value
of the parameter to the shell variable ACCESS_TOKEN for the next step.
4.2.5. mdoc
Generate a DPoP proof JWT to access the credential endpoint. Make sure that (1) the argument given to the-u option of the generate-dpop-proof script is
$CREDENTIAL_ENDPOINT and (2) the -a option must be given to embed the
ath claim in the DPoP proof JWT.
ath claim.
credential parameter in the response is the issued mdoc.
The website “CBOR Zone” (https://cbor.zone/) can be used to decode the mdoc.
Copy the value of the credential parameter, paste it to the textarea of
the “Input” section in the CBOR Zone, choose the base64url radio button, and
press the “Generate” button. You’ll see the content of the mdoc in the CBOR
Diagnostic Notation (RFC 8949, 8. Diagnostic Notation,
RFC 8610, Appendix G. Extended Diagnostic Notation).

4.3. POTENTIAL Interop Event / Track 1 / Light Profile
POTENTIAL is a European organization dedicated to European Digital Identity. The organization has been hosting an interoperability event since spring 2024. The event is divided into six tracks. Tracks 1 and 2 are designated for testing the inteoperability of credential issuers. In Track 1, mdoc is used as the format for verifiable credentials, while SD-JWT VC is used in Track 2. Track 1 defines two profiles. One is called the “light” profile. The other is called the “full” profile. This section explains the steps for the light profile.4.3.1. Settings
4.3.1.1. Authorization Server Settings
The source code of the authorization server is available at
https://github.com/authlete/java-oauth-server. Note that this implementation
is a sample and is not intended for commercial use.
4.3.1.2. Credential Issuer Settings
The source code of the credential issuer is the same as that of the
authorization server.
4.3.1.3. Client Settings
If you need to register additional redirect URIs to this client, or if you need
an independent client dedicated to your use, please contact us.
To Authlete members: New clients should be created under
“Trial” (organization=283415) /
“NextDev” (server=2704222) /
“Authlete Trial” (service=986126671).
4.3.2. Demo Steps
4.3.2.1. Step 1 : Credential Offer
The sample implementation of credential issuer provides a web page where developers can generate an arbitrary credential offer for testing. The URL of the page is https://trial.authlete.net/api/offer/issue. Accessing the web page, you will find a form to configure the content of a credential offer. Edit the form as instructed below.- Input
ingaandingainto the “Login ID” field and the “Password” field. - Edit the “Credential Configuration IDs”. The value should be a JSON array containing the string
potential.light.profile. - Check the “include?” checkbox next to “Authorization Code Grant”.
- Uncheck the “include?” checkbox next to “Pre-Authorized Code Grant”.


issuer_state property in the JSON is the issued
issuer state. In the above example, the value of the issuer state is
tXkAkhSu5N9ORSNES9T64Bd9PAiKn9OmEOT5qDL0lkA.
The issuer state is to be included in the authorization request you will
make later.
4.3.2.2. Step 2 : Code Verifier and Code Challenge
Generate a code verifier and compute the corresponding code challenge (cf. RFC 7636) by using thepkce command
pkce command will print a generated code verifier and the computed code
challenge like below.
4.3.2.3. Step 3 : Authorization Request
Make an authorization request using the authorization code flow (cf. RFC 6749, 4.1) by inputting the following URL in the address bar of your web browser. Don’t forget to replace${ISSUER_STATE} and
${CODE_CHALLENGE} in the URL with the actual values of the issuer state and
the code challenge you have created in the previous steps.
inga and inga into the Login ID field and the Password
field in the login form, and press the “Authorize” button.


code parameter displayed there is the issued
authorization code. In this example, the value of the authorization code is
gR43MQf2olvhMt6KekVDkUOdQPrVYgBiKXMwu_UFnB8.
The authorization code is to be used in the token request in the next section.
Note that the authorization code will expire in 10 minutes, so you have to make
a token request promptly.
4.3.2.4. Step 4 : Token Request
Make a token request using the authorization code flow. Don’t forget to replace${AUTHORIZATION_CODE} and ${CODE_VERIFIER} in the curl command
below with the actual values you have obtained in the previous steps.
access_token property in the JSON is the issued
access token. It needs to be presented when you make a credential request.
The value of the c_nonce property is a nonce that must be included in a
key proof.
4.3.2.5. Step 5 : CWT Key Proof
The authlete/cbor library contains a utility class,CWTKeyProofBuilder, that can generate a CWT key proof. The shell script,
bin/generate-cwt-key-proof, which is included in the repository of the
library, is a wrapper to invoke the utility class from the command line.
A CWT key proof can be generated as shown below. Don’t forget to replace
${NONCE} in the command line with the actual value of c_nonce that has
been issued from the token endpoint in the previous step, and to replace
${PRIVATE_KEY_FILE} with the actual path of a file containing a private
key in the JWK format (cf. RFC 7517). The file, holder.jwk, in
the authlete/oid4vci-demo repository can be used
for the purpose.
generate-cwt-key-proof script will print a CWT key proof like below.
The following is the result of decoding the CWT key proof above using CBOR Zone.
COSE_Key in the protected header is a CBOR byte string, which
wraps the COSE key. The content of the byte string is decoded as follows:
4.3.2.6. Step 6 : Credential Request
Make a credential request with the access token and the CWT key proof. Don’t forget to replace${ACCESS_TOKEN} and ${CWT_KEY_PROOF} in the
command line with the actual values.
credential property in the JSON is the
issued verifiable credential.
4.3.3. Verifiable Credential Format
The CBOR Diagnostic Notation representation of the verifiable credential in the previous section is as follows.In this example, the verifiable credential represents the
IssuerSigned structure,
which is defined in the “8.3.2.1.2.2 Device retrieval mdoc response” section of
ISO/IEC 18013-5:2021 as below.
Unexpectedly, the OID4VCI specification does not specify which CBOR structure
the value of the
Due to this ambiguity, in the previous implementation of Authlete, the
The reason for changing the implementation of Authlete to use the
credential property represents when the format
is mso_mdoc. This is unlikely to be intentional and is simply a
specification flaw.Due to this ambiguity, in the previous implementation of Authlete, the
Document structure was used instead of the IssuerSigned
structure. Interestingly, it appears that the implementation of EUDI Wallet
expects neither the IssuerSigned structure nor the Document
structure. Instead, it seems to expect the DeviceResponse structure.The reason for changing the implementation of Authlete to use the
IssuerSigned structure is because the document for POTENTIAL
Interop Event Track 1 explicitly states that the IssuerSigned
structure should be used.IssuerAuth structure and some other relevant structures are defined
as below.
IssuerAuth and MobileSecurityObjectBytes
give the impression that MobileSecurityObjectBytes
(which starts with a CBOR tag) is directly used as the payload of COSE_Sign1.
However, it is necessary to further convert MobileSecurityObjectBytes
into a byte string.
Therefore, the third element in the "issuerAuth" array, which starts with
h'd81859, represents a byte string containing
MobileSecurityObjectBytes.
You can see the following CBOR structure by decoding that byte string.
The point to note is that the public key embedded in the CWT key proof appears in the verifiable credential as the value of
deviceKey. Please
confirm that the value of COSE_Key in the CWT key proof is identical
to the value of deviceKey in the VC. Both hold the following COSE Key.
Refer to IANA: CBOR Object Signing and Encryption (COSE) for the meanings of the integer labels and integer values in the COSE Key.
4.4. POTENTIAL Interop Event / Track 2 / Light Profile
POTENTIAL is a European organization dedicated to European Digital Identity. The organization has been hosting an interoperability event since spring 2024. The event is divided into six tracks. Tracks 1 and 2 are designated for testing the inteoperability of credential issuers. In Track 1, mdoc is used as the format for verifiable credentials, while SD-JWT VC is used in Track 2. Track 2 defines two profiles. One is called the “light” profile. The other is called the “full” profile. This section explains the steps for the light profile.4.4.1. Settings
4.4.1.1. Authorization Server Settings
The source code of the authorization server is available at
https://github.com/authlete/java-oauth-server. Note that this implementation
is a sample and is not intended for commercial use.
4.4.1.2. Credential Issuer Settings
The source code of the credential issuer is the same as that of the
authorization server.
4.4.1.3. Client Settings
If you need to register additional redirect URIs to this client, or if you need
an independent client dedicated to your use, please contact us.
To Authlete members: New clients should be created under
“Trial” (organization=283415) /
“NextDev” (server=2704222) /
“Authlete Trial” (service=986126671).
4.4.2. Demo Steps
4.4.2.1. Step 1 : Code Verifier and Code Challenge
Generate a code verifier and compute the corresponding code challenge (cf. RFC 7636) by using thepkce command
pkce command will print a generated code verifier and the computed code
challenge like below.
4.4.2.2. Step 2 : Authorization Request
Make an authorization request using the authorization code flow (cf. RFC 6749, 4.1) by inputting the following URL in the address bar of your web browser. Don’t forget to replace${CODE_CHALLENGE}
in the URL with the actual value of the code challenge you have created in
the previous step.
inga and inga into the Login ID field and the Password
field in the login form, and press the “Authorize” button.


code parameter displayed there is the issued
authorization code. In this example, the value of the authorization code is
gR43MQf2olvhMt6KekVDkUOdQPrVYgBiKXMwu_UFnB8.
The authorization code is to be used in the token request in the next section.
Note that the authorization code will expire in 10 minutes, so you have to make
a token request promptly.
4.4.2.3. Step 3 : Token Request
Make a token request using the authorization code flow. Don’t forget to replace${AUTHORIZATION_CODE} and ${CODE_VERIFIER} in the curl command
below with the actual values you have obtained in the previous steps.
access_token property in the JSON is the issued
access token. It needs to be presented when you make a credential request.
The value of the c_nonce property is a nonce that must be included in a
key proof.
4.4.2.4. Step 4 : JWT Key Proof
Generate a JWT Key Proof using the holder keyholder.jwk and the generate-key-proof script.
The JWK file and the script are contained in the oid4vci-demo repository.
Don’t forget to replace $C_NONCE in the following command line with the actual value of the
c_nonce property in the token response you received in the previous step.
generate-key-proof script will generate a JWT Key Proof like below.
Decoding the header and the payload of the JWT Key Proof by base64url will show the following JSONs.
generate-key-proof script can be directly set to
the shell variable JWT_KEY_PROOF by doing the following.
4.4.2.5. Step 5 : Credential Request
Make a credential request with the access token and the JWT key proof. Don’t forget to replace${ACCESS_TOKEN} and ${JWT_KEY_PROOF} in the
command line with the actual values.
credential property in the JSON is the
issued verifiable credential.
4.4.3. Verifiable Credential Format
The value of thecredential parameter in the response is the issued SD-JWT VC.
If the SD-JWT VC is set to the shell variable SD_JWT, the content of the SD-JWT VC
can be decoded by invoking the decode-sd-jwt script as follows.
4.5. POTENTIAL Interop Event / Track 2 / Full Profile
POTENTIAL is a European organization dedicated to European Digital Identity. The organization has been hosting an interoperability event since spring 2024. The event is divided into six tracks. Tracks 1 and 2 are designated for testing the inteoperability of credential issuers. In Track 1, mdoc is used as the format for verifiable credentials, while SD-JWT VC is used in Track 2. Track 2 defines two profiles. One is called the “light” profile. The other is called the “full” profile. This section explains the steps for the full profile.4.5.1. Settings
4.5.1.1. Authorization Server Settings
The source code of the authorization server is available at
https://github.com/authlete/java-oauth-server. Note that this implementation
is a sample and is not intended for commercial use.
4.5.1.2. Credential Issuer Settings
The source code of the credential issuer is the same as that of the
authorization server.
4.5.1.3. Client Settings
If you need to register additional redirect URIs to this client, or if you need
an independent client dedicated to your use, please contact us.
To Authlete members: New clients should be created under
“Trial” (organization=283415) /
“NextDev” (server=2704222) /
“Authlete Trial” (service=986126671).
4.5.2. Demo Steps
4.5.2.1. Step 1 : Code Verifier and Code Challenge
Generate a code verifier and compute the corresponding code challenge (cf. RFC 7636) by using thepkce command
pkce command will print a generated code verifier and the computed code
challenge like below.
4.5.2.2. Step 2 : Client Attestation and Client Attestation PoP
In POTENTIAL’s Track 2 Full Profile, a new client authentication method called “OAuth 2.0 Attestation-Based Client Authentication” is used. For this method, two JWTs need to be prepared. The JWTs are called “Client Attestation” and “Client Attestation PoP”, respectively. The oid4vci-demo repository includes two scripts,generate-client-attestation and
generate-client-attestation-pop, for generating
the JWTs. Their usage is as follows:
To generate a client attestation, a private key of the “client attestation issuer” (hereinafter referred to as “attester”) and a public key of the client application are needed. The attester’s key is used for signing the client attestation. The client’s key is embedded in the client attestation. The oid4vci-demo repository includes an attester’s private key (
attester.jwk) and a client’s private key (client.jwk) for demo. With these
keys, a client attestation can be generated as follows:
The
generate-client-attestation script uses only the
public part of the specified client key, even if a private key
is given. Therefore, the file containing the private key of the client
can be passed to the --client-key option directly.The above example uses
Please note that the current draft (draft 03 as of this writing) of the “OAuth 2.0 Attestation-Based Client Authentication” specification does not specify how to obtain the public key for verifying the signature of a client attestation. It seems that the specification expects ecosystems to determine their own rules for that part, respectively.
Therefore, the current implementation of Authlete does NOT verify the signature of a client attestation, and so Authlete does not care about the value of the attester’s identifier. Verification of the signature of a client attestation must be done by the implementation of your authorization server.
In the future, Authlete may provide mechanisms to aid in the verification step.
https://attester.example.com as the value
of the attester’s identifier. Any value works because the current implementation
of Authlete does not care about the value.Please note that the current draft (draft 03 as of this writing) of the “OAuth 2.0 Attestation-Based Client Authentication” specification does not specify how to obtain the public key for verifying the signature of a client attestation. It seems that the specification expects ecosystems to determine their own rules for that part, respectively.
Therefore, the current implementation of Authlete does NOT verify the signature of a client attestation, and so Authlete does not care about the value of the attester’s identifier. Verification of the signature of a client attestation must be done by the implementation of your authorization server.
In the future, Authlete may provide mechanisms to aid in the verification step.
generate-client-attestation script generates a
client attestation in the JWT format like below:
The following is the base64url-decoded header and payload of the JWT. You can see that the attester’s identifier is used as the value of the
iss claim and the public key of the client is embedded
as the value of the cnf.jwk property.
client.jwk) in the
oid4vci-demo repository, a client attestation PoP
can be generated as follows:
generate-client-attestation-pop script
generates a client attestation PoP in the JWT format like below:
The following is the base64url-decoded header and payload of the JWT. You can see that the client’s identifier is used as the value of the
iss claim and the authorization server’s identifier is specified
as the value of the aud claim.
4.5.2.3. Step 3 : DPoP Proof JWT for PAR Request
To generate a DPoP Proof JWT, thegenerate-dpop-proof
script in the oid4vci-demo repository can be used.
With the key for DPoP demo (dpop.jwk) in the oid4vci-demo repository,
the script can be invoked like below.
The
Because the DPoP Proof JWT being created here is for the PAR request, the URL of the PAR endpoint (
-u option (the short version of the --htu option)
of the generate-dpop-proof script specifies the value of
the htu claim in the DPoP Proof JWT.Because the DPoP Proof JWT being created here is for the PAR request, the URL of the PAR endpoint (
https://trial.authlete.net/api/par)
is specified by the -u option.generate-dpop-proof script generates a DPoP Proof JWT
in the JWT format like below:
The following is the base64url-decoded header and payload of the DPoP Proof JWT. The
htu claim holds the URL of the PAR endpoint.
4.5.2.4. Step 4 : PAR Request
One of the advantages of the PAR endpoint over the authorization endpoint is that the PAR endpoint can perform client authentication. In this demo, we use attestation-based client authentication when accessing the PAR endpoint. The client authentication method requires that two JWTs, namely, a client attestation and a client attestation PoP, be specified by two HTTP headers,OAuth-Client-Attestation and
OAuth-Client-Attestation-PoP.
With the client attestation and the client attestation PoP you created in Step 2,
and the DPoP Proof JWT you created in Step 3, you can make a PAR request by
executing the following command. Please replace ${CLIENT_ATTESTATION},
${CLIENT_ATTESTATION_POP}, ${DPOP_PROOF_JWT_FOR_PAR_REQUEST} and
${CODE_CHALLENGE} in the command line with the actual values you created in
the previous steps.
request_uri property. The value of this property
is a request URI that represents the pre-registered authorization request.
urn:ietf:params:oauth:request_uri:-CYpNdxTlS3S7e0PQKJVehPMnC0iiIk4pqJpD25k0Ws.
You are expected to specify this value as the value of the request_uri
parameter of the authorization request that you will make in the next step.
4.5.2.5. Step 5 : Authorization Request
Please input the following URL in the address bar of your web browser. This is an authorization request to the authorization endpoint of the authorization server. Don’t forget to replace${REQUEST_URI} in the URL with the actual
value of the request URI you obtained in the previous step.
inga and inga as Login ID and Password, and then
click the “Authorize” button.


code parameter displayed there is the issued
authorization code. In this example, the value of the authorization code is
yn1W7SLX9OEGqFZ2D986iPowVnoQtIRpPByBEyiIrBk.
The authorization code will be used in the token request you will make later.
4.5.2.6. Step 6 : DPoP Proof JWT for Token Request
You need to create a new DPoP Proof JWT to access the token endpoint. You cannot reuse the DPoP Proof JWT you created for the PAR request. The following command line can generate the DPoP Proof JWT. Please note that the value of the-u option is the URL of the token endpoint (not the PAR endpoint).
generate-dpop-proof script will generate a JWT like below.
The following is the base64url-decoded header and payload of the DPoP Proof JWT. The
htu claim holds the URL of the token endpoint.
4.5.2.7. Step 7 : Token Request
Now you have the following:- Client Attestattion (JWT)
- Client Attestation PoP (JWT)
- DPoP Proof JWT for Token Request (JWT)
- Authorization Code
- Code Verifier
access_token property is the issued access token. This needs
to be included in the credential request you will make later.
The value of the c_nonce property is the issued nonce. This value needs to be
included in the JWT Key Proofs you will create in the next step.
4.5.2.8. Step 8 : JWT Key Proofs for Credential Request
In POTENTIAL’s Track 2 Full Profile, a new feature introduced by “OpenID4VCI PR 293: rework credential and batch credential endpoint” is used. This new feature enables a client application to request multiple verifiable credentials in a single credential request. To request multiple verifiable credentials, a credential request needs to include multiple key proofs. Therefore, here we are going to generate two JWT Key Proofs with different holder keys. The oid4vci-demo repository contains two holder keys,holder.jwk and holder2.jwk, for demo. With these keys and the
generate-key-proof script, you can generate JWT
Key Proofs as follows. Please replace ${C_NONCE} in the command lines
with the actual value of the c_nonce property in the token response
you received in the previous step before executing the command lines.
The
When the
These steps described above imply that, if your authorization server does not include
The
Authlete will continue to support the
c_nonce property in a token response is optional, so the token
response from your authorization server may not include this property. In that case,
you cannot generate a valid key proof including c_nonce until you get
a valid c_nonce from your credential issuer.When the
c_nonce included in a key proof is invalid, the credential
issuer will include a valid c_nonce in the error response. With the
c_nonce, you can generate a valid key proof.These steps described above imply that, if your authorization server does not include
c_nonce in a token response, your first credential request
with a key proof including a (fake) c_nonce inevitably fails.
Although you know the first request will fail, you need to make the request only
to get a valid c_nonce.The
c_nonce property in a token response is optional, so
authorization server implementations don’t have to include the property in a
token response if they don’t want to. However, there are several people in the
industry who dislike the feature that allows authorization servers to issue
c_nonce and are attempting to remove this feature itself from the
OID4VCI specification. If their attempt succeeded, all initial credential requests
containing a key proof with c_nonce worldwide would inevitably fail.Authlete will continue to support the
c_nonce property in a token
response for harmless backward compatibility with Implementer’s Draft 1 of the
OID4VCI specification, unless the specification is revised to explicitly prohibit
including the property. However, introducing such prohibition would conflict with
RFC 6749, the core
specification of OAuth 2.0, which allows token responses to include arbitrary
response parameters.holder.jwk. Please note that
the content of the jwk claim in the header holds the public key corresponding
to the private key in holder.jwk.
holder2.jwk.
The jwk claim in the header is the public key corresponding to the private
key in holder2.jwk.
4.5.2.9. Step 9 : DPoP Proof JWT for Credential Request
You need to create another DPoP Proof JWT again to access the credential endpoint. In addition to specifying the URL of the credential endpoint as the value of the-u option, this time you need to specify the access token value using
the -a option (short for --at option). This option is necessary to include
the ath claim in the DPoP Proof JWT.
ath claim, which
represents the hash value of the access token.
4.5.2.10. Step 10 : Credential Request
Now you have the following:- Access Token
- DPoP Proof JWT for Credential Request (JWT)
- JWT Key Proof 1 (JWT)
- JWT Key Proof 2 (JWT)
proofs property instead of the proof property. The proofs property
is a new addition introduced by OpenID4VCI PR 293, which
enables the inclusion of multiple key proofs.
The credential endpoint will return a response like below.
credentials property instead
of the credential property. Elements in the credentials array are issued
verifiable credentials. In this example, the credentials array contains two
verifiable credentials because the credential request contained two key proofs.
The format of the verifiable credentials is SD-JWT. They can be decoded using
the decode-sd-jwt script in the
oid4vci-demo repository.
The first verifiable credetial is decoded as follows:
cnf.jwk property matches the
public key embedded in the first key proof.
cnf.jwk property in the second verifiable credential
matches the public key embedded in the second key proof.