```##### 2.9.1.2. Other Key Proofs
This document does not explain other key proofs such as CWT-based key proof.
Please refer to the OID4VCI specification for them.
#### 2.9.2. c_nonce
As the primary countermeasure against key proof replay, the credential issuer may require the inclusion of the `nonce` 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.
[](/oid4vci)
The wallet uses the value of the `c_nonce` response parameter as the value of the `nonce` claim in a key proof JWT.
[](/oid4vci)
The wallet includes the key proof JWT in a credential request.
[](/oid4vci)
If the `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.
[](/oid4vci)
If necessary, the wallet can regenerate a new key proof using the `c_nonce` value provided by the credential endpoint and make a credential request again with the fresh key proof.
[](/oid4vci)
The diagram below provides an overview of `c_nonce`.
[](/oid4vci)
#### 2.9.3. 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.
[](/oid4vci)
A `credential_response_encryption` JSON object may be present
for credential response encryption, but it is not discussed here.
##### 2.9.3.1. Credential Information in Credential Request
Credential information in a credential request includes a mandatory `"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.
[](/oid4vci)
The credential information is a description about the verifiable credential that the wallet wants to obtain. As implied by the example in the diagram above, taken from the OID4VCI specification, this description goes beyond merely identifying an issuable credential from among the issuable credentials associated with the access token. For instance, the intention of the example credential request is to request a verifiable credential in the format of `jwt_vc_json` that includes the `given_name`, `family_name` and `degree` claims only.
However, there are the following issues here:
1. It’s not easy to determine which of the issuable credentials meet the specified conditions.
2. There’s a possibility that multiple issuable credentials may satisfy the conditions.
3. Minor differences in conditions can lead to the selection of a different issuable credential.
4. It’s not easy to confirm whether the presented access token has the permission to request verifiable credentials that meet the specified conditions.
Simply put, this specification lacks considerations for implementations.
The problem reported by [Issue 175](https://github.com/openid/OpenID4VCI/issues/175)
is an example that can be caused by the flaw in this specification.
Therefore, unless the specification is improved, it is likely that
credential issuer implementations will issue verifiable credentials with fixed structures,
ignoring finer conditions specified at runtime (in access token requests or credential requests).
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](https://github.com/openid/OpenID4VCI/issues/197)
for further discussions.
##### 2.9.3.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.
[](/oid4vci)
The `"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.
[](/oid4vci)
The diagram below is an overview of a credential request.
[](/oid4vci)
#### 2.9.4. Credential Response
A credential response is an HTTP response containing JSON.
##### 2.9.4.1. Credential Response with Verifiable Credential
When a verifiable credential is successfully issued, it is placed in the JSON as the value of the `"credential"` property.
[](/oid4vci)
For instance, in the case of SD-JWT-based verifiable credentials conforming to [SD-JWT VC](https://datatracker.ietf.org/doc/draft-ietf-oauth-sd-jwt-vc/), the `"credential"` property is a JSON string in the format of SD-JWT.
[](/oid4vci)
In addition, the credential response may contain the `c_nonce` and `c_nonce_expires_in` response parameters, as explained previously.
[](/oid4vci)
Let’s dive into some details of an SD-JWT-based verifiable credential.
[](/oid4vci)
An SD-JWT consists of an issuer-signed JWT, zero or more disclosures, and an optional key binding JWT. Tildes (`~`) 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.
```
Issuer-Signed-JWT>~Disclosure-1>\`}...Disclosure-N>~
```The first component in an SD-JWT is an issuer-signed JWT. As a standard JWT, the header and payload of the issuer-signed JWT can be base64url-decoded.
[](/oid4vci)
The following are important points to note.
1. The value of the `typ` header parameter is `"vc+sd-jwt"`.
2. The payload contains `"cnf"."jwk"` for key binding.
3. The payload contains the `"_sd_alg"` property, which indicates the hash algorithm used for disclosures.
4. 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.
The example of SD-JWT-based verifiable credential contains four disclosures.
[](/oid4vci)
By base64url-decoding the disclosures, the original JSON arrays will appear.
[](/oid4vci)
The digest values of the disclosures are computed using the hash algorithm indicated by the `"_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.
[](/oid4vci)
The diagram below is an overview of a credential response with an SD-JWT-based verifiable credential.
[](/oid4vci)
##### 2.9.4.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.
```http
HTTP/1.1 202 Accepted
Content-Type: application/json
Cache-Control: no-store
```The transaction ID is intended to be used later when the wallet sends a deferred credential request to the deferred credential endpoint of the credential issuer.
##### 2.9.4.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.
```http
HTTP/1.1 400 Bad Request
Content-Type: application/json
Cache-Control: no-store
```If a required key proof is missing or incorrect due to reasons like the `nonce` claim’s absence or expiration, the error code `"invalid_proof"` is used. Here is an example from the specification in such a case.
```http
HTTP/1.1 400 Bad Request
Content-Type: application/json
Cache-Control: no-store
```#### 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.
```http
POST /deferred_credential HTTP/1.1
Host: issuer.example.com
Content-Type: application/json
Authorization: Bearer czZCaGRSa3F0MzpnWDFmQmF0M2JW
```#### 2.9.6. Deferred Credential Response
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.
```http
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
```In the event of an unsuccessful issuance, an error response will be returned with the `"error"` parameter. Particularly, when the requested verifiable credential is not yet ready, the error code `"issuance_pending"` is used.
```http
HTTP/1.1 400 Bad Request
Content-Type: application/json
Cache-Control: no-store
```#### 2.9.7. Batch Credential Request
A wallet can request multiple verifiable credentials at a time by sending a batch credential request to the batch credential endpoint of the credential issuer.
A batch credential request is an HTTP POST request containing JSON, which includes a `"credential_requests"` JSON array. The array is a list of JSON objects, each of which represents a credential request.
[](/oid4vci)
Each credential request contains credential information and may contain an optional key proof.
[](/oid4vci)
It is allowed for credential requests in a batch credential request to specify different credential formats and have different key proofs. The opposite is also true. The credential requests may specify the same credential format and have the same key proof.
[](/oid4vci)
The diagram below is an overview of a batch credential request.
[](/oid4vci)
#### 2.9.8. Batch Credential Response
A batch credential response is an HTTP response containing JSON, which includes a `"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.
[](/oid4vci)
Each credential response contains either a verifiable credential or a transaction ID.
[](/oid4vci)
In addition, a batch credential response may contain `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.
[](/oid4vci)
The diagram below is an overview of a batch credential response.
[](/oid4vci)
### 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](https://www.rfc-editor.org/rfc/rfc7515.html#section-4.1.6)) will be used for that purpose.
#### 2.10.2. Embedding within Entity Configuration
Another method utilizes the [OpenID Federation](https://openid.net/specs/openid-federation-1_0.html) specification and embeds the public key within the entity configuration of the credential issuer.
The Italian ecosystem has defined `openid_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.
[](/oid4vci)
At the time of this writing, `"jwks"`, `"jwks_uri"`, and `"signed_jwks_uri"` have not been defined as credential issuer metadata.
#### 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.
[](/oid4vci)
The well-known path returns JSON containing the JWT VC issuer’s metadata.
The `"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 OID4VCI specification defines rules for the issuance of verifiable credentials. The two major topics in the specification are “access token issuance” and “credential issuance”.
For access token issuance, the specification defines several methods for
specifying issuable credentials, which include,
(1) using the pre-authorized code in a credential offer,
(2) using the issuer state in a credential offer,
(3) using RAR objects with `"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](https://www.iso.org/standard/69084.html)). 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
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.
[](/oid4vci)
The Authlete architecture inevitably requires developers to build frontend servers,
but in return, developers receive the following benefits.
1. Any technical components of developer’s choice
- User authentication method
- User management system
- API gateway
- Programming language
- Web framework
- Cloud service
2. 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.
3. Full control over end-user facing frontend servers
- Corporate brand management across all aspects of UI/UX.
4. 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](https://www.youtube.com/watch?v=hK7ORyfTpvI)", a panel discussion
on this topic held at EIC 2023.
### 3.2. Authlete Configuration
#### 3.2.1. Authlete Version
The OID4VCI specification is supported from Authlete 3.0, which is scheduled
to be released around April 2024. Until then, a trial server is available for
customers and business partners. If you are interested in trying OID4VCI,
please [contact us](https://www.authlete.com/contact/).
[](/oid4vci)
#### 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.
```java-properties
feature.verifiable_credentials.enabled=true
```#### 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. |
| `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` | stringarray | 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 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. |
| `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. |
| `credentialResponseEncryptionAlgValuesSupported` | stringarray | 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](https://authlete.github.io/authlete-java-common/com/authlete/common/types/JWEAlg.html) enum entries such as `"ECDH_ES"`.
Only asymmetric algorithms are accepted. |
| `credentialResponseEncryptionEncValuesSupported` | stringarray | 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](https://authlete.github.io/authlete-java-common/com/authlete/common/types/JWEEnc.html) enum entries such as `"A256GCM"`. |
| `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. |
| `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 of `c_nonce` in seconds.
When the token endpoint of the authorization server issues an access
token usable for verifiable credential issuance, it also issues a
`c_nonce` alongside the access token. In addition, the
credential endpoint and the batch credential endpoint of the credential
issuer issue a new `c_nonce` when the presented
`c_nonce` has already expired. This property is used as
the lifetime of such `c_nonce`s.
If the value of this property is 0 or negative, the default value per
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](https://www.rfc-editor.org/rfc/rfc7519.html),
[Section 4.1.4](https://www.rfc-editor.org/rfc/rfc7519.html#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](https://www.rfc-editor.org/rfc/rfc7517.html),
[Section 4.5](https://www.rfc-editor.org/rfc/rfc7517.html#section-4.5)) when this `credentialJwks` property
is updated, Authlete will automatically insert the `kid`
property into such JWKs. The JWK thumbprint
([RFC 7638](https://www.rfc-editor.org/rfc/rfc7638.html))
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)](https://datatracker.ietf.org/doc/draft-ietf-oauth-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.
[](/oid4vci)
#### 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.
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.
| | Authlete 2.x | Authlete 3.0 |
| --- | --- | --- |
| Protection | API key & API secret | Access token |
| Web Console | The service owner console and the developer console | A single console |
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/````/auth/authorization`, where `` represents the identifier of a service (i.e., the service API key in Authlete 2.x).
| Authlete Version | API Path Example |
| --- | --- |
| Authlete 2.x | `/api/auth/authorization` |
| Authlete 3.0 | `/api/````/auth/authorization` |
In this document, as well as in other documents, the prefix `/api/` for API paths is omitted.
These changes are not insignificant, but their impact on programs can be
minimized by absorbing the differences at the library layer. For instance,
developers using the sample authorization server written in Java
([authlete/java-oauth-server](https://github.com/authlete/java-oauth-server)) and switching from
Authlete 2.x to Authlete 3.0 only need to modify the content of the
configuration file (`authlete.properties`) from:
```java-properties
# For Authlete 2.x
base_url = ...
service.api_key = ..
service.api_secret = ...
```to:
```java-properties
# For Authlete 3.0
api_version = V3
base_url = ...
service.api_key = ...
service.access_token = ...
```
### 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:
[](/oid4vci)
that represents “`openid-credential-offer://?credential_offer=`”
where `` holds the following credential offer.
```json
}
}
```The credential issuer may instead show a hyperlink like below:
- `openid-credential-offer://?credential_offer_uri=```
where `` 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 andContent-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.
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. |
For example, the following command lines create a credential offer.
```shell
$ BASE_URL=https://nextdev-api.authlete.net
$ SERVICE_ID=986126671
$ ACCESS_TOKEN=$
$ curl -s $/api/$/vci/offer/create \
-H "Authorization: Bearer $" \
-H "Content-Type: application/json" \
--data '
'
```The `/vci/offer/create` API returns JSON like below.
```json
}}}",
"expiresAt": 1703929674224,
"identifier": "9gjVvas8Q5BkkrkSfZv-DbsBYJvlw6ZPMK-TeCkQDEc",
"issuerStateIncluded": false,
"preAuthorizedCode": "rS8D7asTTL8MaXM5yLjQvaAMmPmierRW6oeK-4JP4Uk",
"preAuthorizedCodeGrantIncluded": true,
"subject": "1001",
"txCode": "123456",
"txCodeInputMode": "numeric"
}
}
```The `"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.
```json
\`}
}
}
```With the value of the `"credentialOffer"` property, you can construct a URL
by concatenating the following components:
1. A credential offer endpoint. For example, `openid-credential-offer://`.
2. `?credential_offer=`.
3. URL-encoded `"credentialOffer"` value.
`
openid-credential-offer://?credential_offer=%7B%22credential_issuer%22%3A%22https%3A%2F%2Ftrial.authlete.net%22%2C%22credential_configuration_ids%22%3A%5B%22IdentityCredential%22%5D%2C%22grants%22%3A%7B%22urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Apre-authorized_code%22%3A%7B%22pre-authorized_code%22%3A%22rS8D7asTTL8MaXM5yLjQvaAMmPmierRW6oeK-4JP4Uk%22%2C%22tx_code%22%3A%7B%22length%22%3A6%2C%22input_mode%22%3A%22numeric%22%7D%7D%7D%7D`
The request to and the response from the `/vci/offer/create` API are represented
by the `CredentialOfferCreateRequest` and
`CredentialOfferCreateResponse` Java
classes in the [authlete-java-common](https://github.com/authlete/authlete-java-common) library, respectively.
Please refer to the library’s [JavaDoc](https://authlete.github.io/authlete-java-common/) for details.
#### 3.4.2. The `/vci/offer/info` API
The `/vci/offer/info` API returns information about a credential offer.
This API accepts the `identifier` request parameter that specifies the
identifier of a credential offer.
| Request to the /vci/offer/info API |
| --- |
| HTTP Method andContent-Type | GET | (path parameters) |
| POST | `application/json` |
| POST | `application/x-www-form-urlencoded` |
| Request Parameters | `identifier` | The identifier of a credential offer. When the API call is an HTTP GET
request, the identifier is specified as the last path component like
`/vci/offer/info/`. |
The identifier is included in the response from the `/vci/offer/create` API.
The value of the `"identifier"` property in the `"info"` object is the identifier.
In the example in the previous section, its value is
`9gjVvas8Q5BkkrkSfZv-DbsBYJvlw6ZPMK-TeCkQDEc`.
The following command lines query information about the credential offer
created in the previous section.
```shell
$ CREDENTIAL_OFFER_IDENTIFIER=9gjVvas8Q5BkkrkSfZv-DbsBYJvlw6ZPMK-TeCkQDEc
$ curl -s $/api/$/vci/offer/info/$ \
-H "Authorization: Bearer $"
```The `/vci/offer/info` API returns JSON like below, which is almost the same
as the response from the `/vci/offer/create` API.
```json
}}}",
"expiresAt": 1703929674000,
"identifier": "9gjVvas8Q5BkkrkSfZv-DbsBYJvlw6ZPMK-TeCkQDEc",
"issuerStateIncluded": false,
"preAuthorizedCode": "rS8D7asTTL8MaXM5yLjQvaAMmPmierRW6oeK-4JP4Uk",
"preAuthorizedCodeGrantIncluded": true,
"subject": "1001",
"txCode": "123456",
"txCodeInputMode": "numeric"
}
}
```The main purpose of the `/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.
[](/oid4vci)
If such endpoint is available, you can construct a URL by concatenating the
following components:
1. A credential offer endpoint. For example, `openid-credential-offer://`.
2. `?credential_offer_uri=`.
3. URL-encoded URL of the endpoint including the identifier of the credential offer. For example, `https://trial.authlete.net/api/offer/9gjVvas8Q5BkkrkSfZv-DbsBYJvlw6ZPMK-TeCkQDEc`.
`
openid-credential-offer://?credential_offer_uri=https%3A%2F%2Ftrial.authlete.net%2Fapi%2Foffer%2F9gjVvas8Q5BkkrkSfZv-DbsBYJvlw6ZPMK-TeCkQDEc`
#### 3.4.3. Credential Offer Issuance Example
The sample authorization server implementation written in Java,
[authlete/java-oauth-server](https://github.com/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](https://trial.authlete.net), and the
endpoint is active for trial purposes at [https://trial.authlete.net/api/offer/issue](https://trial.authlete.net/api/offer/issue).
[](/oid4vci)
The HTML page requires user authentication. The test accounts embedded in
java-oauth-server can be used. However, if you want to issue an mdoc-based
VC, please use `inga`.
| Subject | Login ID | Password |
| --- | --- | --- |
| 1001 | `john` | `john` |
| 1002 | `jane` | `jane` |
| 1003 | `max` | `max` |
| 1004 | `inga` | `inga` |
### 3.5. Credential Endpoint Implementation
The credential endpoint can be implemented using the following Authlete APIs.
| | Authlete API | Description |
| --- | --- | --- |
| 1 | `/auth/introspection` | validates the presented access token, and returns the information about the access token. |
| 2 | `/vci/single/parse` | parses and validates the received credential request, and returns the information about the credential request. |
| 3 | `/vci/single/issue` | issues a verifiable credential or a transaction ID, and prepares the credential response. |
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.
[](/oid4vci)
The implementation extracts the access token from the credential request and
passes it to Authlete’s `/auth/introspection` API.
[](/oid4vci)
The `/auth/introspection` API validates the access token, and returns
information about the access token.
[](/oid4vci)
If the access token is valid, the endpoint implementation sends the
access token and the message body of the credential request to the
`/vci/single/parse` API.
[](/oid4vci)
You might wonder why the access token is sent to the `/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.
The `/vci/single/parse` API parses and validates the credential request, and returns the information about the credential request.
[](/oid4vci)
The endpoint implementation prepares a “credential issuance order”, which
contains necessary information for Authlete to issue a verifiable credential.
The details about this preparation will be discussed later.
[](/oid4vci)
The endpoint implementation sends the credential issuance order and the access
token to the `/vci/single/issue` API.
[](/oid4vci)
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.
The `/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.
[](/oid4vci)
The endpoint implementation builds an HTTP response that represents the credential
response from the endpoint to the wallet. The response content prepared by the
`/vci/single/issue` API can be used as the message body of the credential
response.
[](/oid4vci)
Finally, the credential endpoint returns the credential response to the wallet.
[](/oid4vci)
The following diagram illustrates the processing steps within a credential
endpoint implementation.
[](/oid4vci)
#### 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](https://authlete.github.io/authlete-java-common/com/authlete/common/dto/IntrospectionResponse.html))
holds the value of the subject.
[](/oid4vci)
##### 3.5.1.2. Credential Issuance Order Step 2
Retrieve information about the user identified by the subject from the user database.
[](/oid4vci)
##### 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.
[](/oid4vci)
##### 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 in the response from the `/vci/single/parse`
API (cf. [CredentialSingleParseResponse](https://authlete.github.io/authlete-java-common/com/authlete/common/dto/CredentialSingleParseResponse.html)) holds
various information about the credential request. The combination of the `"format"`
property and the `"details"` property in the `"info"` object represent the
credential information.
[](/oid4vci)
The value of the `"details"` property is a string. The string needs to be parsed
as a JSON object. The content of the JSON object is almost the same as the
credential request except that it does not contain the `"format"` parameter,
the `"proof"` parameter, and the `“credential_response_encryption”`
parameter.
##### 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.
[](/oid4vci)
However, if you are a programmer, you can understand that the current OID4VCI
specification makes it challenging to implement this step. Furthermore, in the
case of SD-JWT VC, there is a proposal to make `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.
##### 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.
[](/oid4vci)
##### 3.5.1.7. Credential Issuance Order Step 7
Build a credential issuance order using the collected data.
[](/oid4vci)
A credential issuance order is a JSON object that has the properties listed
in the following table.
| Property | Type | Description |
| --- | --- | --- |
| `requestIdentifier` | string | The identifier of the credential request which has been assigned by Authlete. The `info.identifier` property in the response from the `/vci/single/parse` API is the identifier. This property is mandatory. |
| `credentialPayload` | string | The additional payload added to the VC being issued. The format of this string must be a JSON object. The set of the user claims should be converted into JSON and set to this property. This parameter is optional. |
| `issuanceDeferred` | boolean | The flag indicating whether to defer the credential issuance. When this property is `true`, the `/vci/single/issue` API issues a transaction ID instead of a VC. |
| `credentialDuration` | integer | The duration of the VC in seconds. If the value of this property is a positive number, the value is used as the duration. If the value is 0, the default duration of the service is used. If the value is a negative number, the VC will not have an expiration time. |
| `signingKeyId` | string | The key ID of the private key that should be used for signing the VC being issued. If omitted, Authlete will select a key automatically. |
##### 3.5.1.8. Credential Issuance Order Step 8
Prepare a request to the `/vci/single/issue` API (cf. [CredentialSingleIssueRequest](https://authlete.github.io/authlete-java-common/com/authlete/common/dto/CredentialSingleIssueRequest.html)).
[](/oid4vci)
| 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.
[](/oid4vci)
##### 3.5.1.10. Credential Issuance Order Steps Summary
The following diagram is a summary of the steps for preparing a credential issuance order.
[](/oid4vci)
### 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](https://console.authlete.com/).
#### 3.7.1. Service Settings
To enable `oid4vci` in Authlete Service Settings:
1. Log in to the [Authlete Management Console](https://console.authlete.com/)
2. Click on your Organization name and choose your Service.
3. Navigate to Service Settings >\`} Verifiable Credentials > General
4. Under the `Verifiable Credentials Feature` section, press `Enable` to turn on support for Verifiable Credentials.
5. Optionally, enable the `Anonymous Access` property if you want to allow token requests by unidentifiable client applications.
6. Click the `Save Changes` button to apply the updates.

To configure `oid4vci` Credential Issuer Metadata Properties:
1. Navigate to Service Settings > Verifiable Credentials > Credential Issuer Metadata
2. Configure the metadata properties to suit your requirements. The following properties correspond to the metadata defined in the [OID4VCI specification](https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html):
- Authorization Servers
- Credential Issuer Identifier
- Credential Endpoint
- Batch Credential Endpoint
- Deferred Credential Endpoint
- Supported Credentials
- Anonymous Access
3. Click the `Save Changes` button to apply the updates.

#### 3.7.2. Client Settings
To configure `oid4vci` in Authlete Client Settings:
1. Log in to the [Authlete Management Console](https://console.authlete.com/)
2. Click on your Organization name and choose your Service.
3. Navigate to Client Settings > Verifiable Credentials > General
4. Under the `Credential Response Encryption` section, enable `Require` option to turn on support for response encryption.
5. Click the `Save Changes` button to apply the updates.

## 4. OID4VCI Demo
### 4.1. Pre-Authorized Code Flow + Key Proof + SD-JWT VC
#### 4.1.1. Setup
Download the resources used in this demo.
```shell
git clone [email protected]:authlete/oid4vci-demo.git
cd oid4vci-demo
```Set up some shell variables for this demo.
```shell
CLIENT_ID=218232426
TOKEN_ENDPOINT=https://trial.authlete.net/api/token
CREDENTIAL_ISSUER=https://trial.authlete.net
CREDENTIAL_ENDPOINT=https://trial.authlete.net/api/credential
```#### 4.1.2. Pre-Authorized Code
Access [https://trial.authlete.net/api/offer/issue](https://trial.authlete.net/api/offer/issue) to generate a
“credential offer” that contains a “pre-authorized code”.
[](/oid4vci)
The page displayed at the URL provides a form to create an arbitrary
credential offer for demo purposes. If “Pre-authorized code grant included”
in the form is checked, a pre-authorized code will be included in the
credential offer being issued.
Input `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.
[](/oid4vci)
The result page will show a QR code which represents a URL including a
credential offer. The content of the credential offer is shown in the
JSON placed under the QR code. The value of the `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.
```shell
PRE_AUTHORIZED_CODE=NH9udMon5pTuuvbsNsHUNWf8tpU__9wt-gsO9LeYthc
```#### 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.
```shell
curl -s $TOKEN_ENDPOINT \
-d client_id=$CLIENT_ID \
-d grant_type=urn:ietf:params:oauth:grant-type:pre-authorized_code \
-d pre-authorized_code=$PRE_AUTHORIZED_CODE
```The token endpoint will return a response like below.
```json
```The response will contain the `access_token` parameter and the `c_nonce` parameter.
Set the values of the response parameters to shell variables for later use.
```shell
ACCESS_TOKEN=xj2YRmSV-_e15n7mTXSvkCH-Yw-XklRagEHF5WXE7R4
C_NONCE=EhTC8LA6kVrrO6_XiC7N6N_wXdma2Zs1LHAQBZ5E0T0
```#### 4.1.4. Key Proof
Generate a “key proof JWT” using the holder key `holder.jwk` and the
`generate-key-proof` script. The JWK file and the script are contained in the
[oid4vci-demo repository](https://github.com/authlete/oid4vci-demo).
```shell
./generate-key-proof \
-i $CREDENTIAL_ISSUER \
-k holder.jwk \
-c $CLIENT_ID \
-n $C_NONCE
```The `generate-key-proof` script will generate a key proof JWT like below.
`
eyJ0eXAiOiJvcGVuaWQ0dmNpLXByb29mK2p3dCIsImFsZyI6IkVTMjU2IiwiandrIjp7ImNydiI6IlAtMjU2Iiwia3R5IjoiRUMiLCJ4IjoiUFN4UXJEMnpsMF9tWGNBcXoxbWdxU2VCb0Jobm14Mnl4QkVwckJZOEYyMCIsInkiOiJ4VjhmYmkxRlNvc1V1bkxldUxOdUxrSmlxbVk2VEtpTW51ci1HbjJ3UjEwIn19.eyJpc3MiOiIyMTgyMzI0MjYiLCJhdWQiOiJodHRwczovL3RyaWFsLmF1dGhsZXRlLm5ldCIsImlhdCI6MTcwMzg0NzM3Niwibm9uY2UiOiJFaFRDOExBNmtWcnJPNl9YaUM3TjZOX3dYZG1hMlpzMUxIQVFCWjVFMFQwIn0.6l8QnPTclDUoWH5PsVsZQDauA_HcIVDGxU9-TfezflIIAzTFgeC5nTr5rLBkEIgcfUvkUOwKqlM06LdVVwTZlw`
Decoding the header and the payload of the key proof JWT by base64url will show the following JSONs.
```json
}
``````json
```The result of executing the `generate-key-proof` script can be directly set to
the shell variable `KEY_PROOF_JWT` by doing the following.
```shell
KEY_PROOF_JWT=`./generate-key-proof -i $CREDENTIAL_ISSUER -k holder.jwk -c $CLIENT_ID -n $C_NONCE`
```#### 4.1.5. SD-JWT VC
Send a “credential request” with the generated key proof JWT to the “credential endpoint”.
```shell
curl -s $CREDENTIAL_ENDPOINT \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
--data ''"
}
}'
```The credential endpoint will return a response like below.
```json
```The value of the `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.
```shell
./decode-sd-jwt $SD_JWT
```The result will look like below.
```json
\`},
"iat": 1703847605
}
```
### 4.2. Authorization Code Flow + PAR + DPoP + mdoc
#### 4.2.1. Setup
Download the resources used in this demo.
```shell
git clone [email protected]:authlete/oid4vci-demo.git
cd oid4vci-demo
```Set up some shell variables for this demo.
```shell
CLIENT_ID=218232426
TOKEN_ENDPOINT=https://trial.authlete.net/api/token
CREDENTIAL_ISSUER=https://trial.authlete.net
CREDENTIAL_ENDPOINT=https://trial.authlete.net/api/credential
PAR_ENDPOINT=https://trial.authlete.net/api/par
```
#### 4.2.2. Request URI
Generate a “DPoP proof JWT” ([RFC 9449](https://www.rfc-editor.org/rfc/rfc9449.html)) using `dpop.jwk`, a private key for DPoP,
and the `generate-dpop-proof` script.
```shell
DPOP_PROOF_JWT=`./generate-dpop-proof -k dpop.jwk -m POST -u $PAR_ENDPOINT`
```The `generate-dpop-proof` script will generate a DPoP proof JWT like below.
`
eyJ0eXAiOiJkcG9wK2p3dCIsImFsZyI6IkVTMjU2IiwiandrIjp7ImNydiI6IlAtMjU2Iiwia3R5IjoiRUMiLCJ4IjoiaEdmcXpHWGdhbzFRZ1ZJVFk2a2lIWU9LYmFMWEJ4VHFQSmE0RU9pbXhoSSIsInkiOiJFMUtpQV9mQTJ4OElycnlzb0dkbkJUTUI1LW8zRUpUX01nUUFfSG1HdTlNIn19.eyJqdGkiOiJoRm9HQkFBN3ZXTHExbWJ6IiwiaHRtIjoiUE9TVCIsImh0dSI6Imh0dHBzOi8vdHJpYWwuYXV0aGxldGUubmV0L2FwaS9wYXIiLCJpYXQiOjE3MDM4NjQ5ODR9.9VZtrwjASCEeO6v0SuGqEttYtoHORtGMNn95mSx4uNv04oA8hSDDBo4CoPQiaGsEjunJ_d_zKR7VsrF9M8BBZA`
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.
```json
\`}
``````json
```Send a PAR request to the PAR endpoint. The points here are (1) that the PAR
request contains the `DPoP` header and (2) that the `scope` parameter contains
`org.iso.18013.5.1.mDL`.
```shell
curl -s $PAR_ENDPOINT \
-H "DPoP: $DPOP_PROOF_JWT" \
-d client_id=$CLIENT_ID \
-d response_type=code \
-d scope=org.iso.18013.5.1.mDL
```This `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`.
```json
,
...
}
}
}
},
...
}
```The PAR endpoint will return a response like below. The value of the
`request_uri` parameter in the response is the issued request URI.
It will be used in the next step.
```json
```
#### 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.
```
https://trial.authlete.net/api/authorization?client_id=218232426&request_uri=$REQUEST_URI
```
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.
[](/oid4vci)
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.
[](/oid4vci)
#### 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`).
```shell
DPOP_PROOF_JWT=`./generate-dpop-proof -k dpop.jwk -m POST -u $TOKEN_ENDPOINT`
```Decoding the header and the payload of the DPoP proof JWT by base64url will
show the following JSONs. The `htu` claim in the payload should hold the
URL of the token endpoint.
```json
}
``````json
```Send a token request using the authorization code flow to the token endpoint.
Don’t forget to set the authorization code issued in the previous step to the shell
variable `AUTHORIZATION_CODE` before executing the following command.
```shell
AUTHORIZATION_CODE=QaPvTUqX-aPDnrcFoCcYDZHW66RzC_vfi6EDq7derNs
``````shell
curl -s $TOKEN_ENDPOINT \
-H "DPoP: $DPOP_PROOF_JWT" \
-d client_id=$CLIENT_ID \
-d grant_type=authorization_code \
-d code=$AUTHORIZATION_CODE
```The token endpoint will return a response like below.
```json
```The response will contain the `access_token` parameter. Please set the value
of the parameter to the shell variable `ACCESS_TOKEN` for the next step.
```shell
ACCESS_TOKEN=T01u7-43MOA17hB8DqW-dEaBqUpStWtitYoVW1ewlH4
```
#### 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.
```shell
DPOP_PROOF_JWT=`./generate-dpop-proof -k dpop.jwk -m POST -u $CREDENTIAL_ENDPOINT -a $ACCESS_TOKEN`
```Decoding the header and the payload of the DPoP proof JWT by base64url will
show the following JSONs. The payload contains the `ath` claim.
```json
\`}
``````json
```Send a “credential request” with the DPoP proof JWT and the access token
to the “credential endpoint”.
```shell
curl -s $CREDENTIAL_ENDPOINT \
-H "DPoP: $DPOP_PROOF_JWT" \
-H "Authorization: DPoP $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
--data ',
"given_name": ,
"birth_date": ,
"issue_date": ,
"expiry_date": ,
"issuing_country": ,
"document_number": ,
"driving_privileges":
\`}
}
}'
```The credential endpoint will return a response like below.
```json
```The value of the `credential` parameter in the response is the issued mdoc.
The website “CBOR Zone” ([https://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](https://www.rfc-editor.org/rfc/rfc8949#section-8),
[RFC 8610, Appendix G. Extended Diagnostic Notation](https://www.rfc-editor.org/rfc/rfc8610#appendix-G)).
[](/oid4vci)
```
>>\`}),
> 24(
>>\`}),
> 24(
>>\`}),
> 24(
>>\`}),
> 24(
>>\`}),
> 24(
>>\`}),
> 24(
>>\`}),
> 24(
> ]
> \`}
>>\`})
> ]
> },
> "issuerAuth": [
> h'a10126',
> ,
> 24(
> },
> "docType": "org.iso.18013.5.1.mDL",
> "validityInfo":
> \`}
>>\`}),
> h'f2720d4e61e2d0deb0cb634736f1726efb97e9e9df988ab4a00a423ebb561d1744726c3712a85ff40944b3eb2f5bb9f07b890dbc3203a7357b006e966e005003'
> ]
> }
> }
> ```
> ### 4.3. POTENTIAL Interop Event / Track 1 / Light Profile
> [POTENTIAL](https://www.digital-identity-wallet.eu/) 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
> | Parameter | Value |
> | --- | --- |
> | Issuer Identifier | `https://trial.authlete.net` |
> | Authorization Endpoint | `https://trial.authlete.net/api/authorization` |
> | Token Endpoint | `https://trial.authlete.net/api/token` |
> | Discovery Endpoint | `[https://trial.authlete.net/.well-known/openid-configuration](https://trial.authlete.net/.well-known/openid-configuration)` |
> | Entity Configuration | `[https://trial.authlete.net/.well-known/openid-federation](https://trial.authlete.net/.well-known/openid-federation)` |
> The source code of the authorization server is available at
> [https://github.com/authlete/java-oauth-server](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
> | Parameter | Value |
> | --- | --- |
> | Issuer Identifier | `https://trial.authlete.net` |
> | Credential Endpoint | `https://trial.authlete.net/api/credential` |
> | Metadata Endpoint | `[https://trial.authlete.net/.well-known/openid-credential-issuer](https://trial.authlete.net/.well-known/openid-credential-issuer)` |
> | Entity Configuration | `[https://trial.authlete.net/.well-known/openid-federation](https://trial.authlete.net/.well-known/openid-federation)` |
> The source code of the credential issuer is the same as that of the
> authorization server.
> ##### 4.3.1.3. Client Settings
> | Parameter | Value |
> | --- | --- |
> | Client ID | `track1_light` |
> | Client Type | public (= [client authentication](https://medium.com/@darutk/oauth-2-0-client-authentication-4b5f929305d4) is not required) |
> | Redirect URIs | `https://nextdev-api.authlete.net/api/mock/redirection``eudi-openid4ci://authorize/` |
> 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](https://www.authlete.com/contact/).
> 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](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.
> 1. Input `inga` and `inga` into the “Login ID” field and the “Password” field.
> 2. Edit the “Credential Configuration IDs”. The value should be a JSON array containing the string `potential.light.profile`.
> 3. Check the “include?” checkbox next to “Authorization Code Grant”.
> 4. Uncheck the “include?” checkbox next to “Pre-Authorized Code Grant”.
> [](/oid4vci)
> Press the “Submit” button after editing the form, and you will find a QR code
> that represents a URL containing the generated credential offer.
> [](/oid4vci)
> The JSON under the QR code represents the content of the credential offer.
> The value of the `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](https://www.rfc-editor.org/rfc/rfc7636.html)) by using the `pkce` command
> ```shell
> git clone [email protected]:authlete/oid4vci-demo.git
> cd oid4vci-demo
> ./pkce
> ```The `pkce` command will print a generated code verifier and the computed code
> challenge like below.
> ```shell
> CODE_VERIFIER=gzRNlV7DLS_HyKMQKQMrzgYQ8aY3H2rVJ3iIlYK0cjE
> CODE_CHALLENGE=j_4gpG9Kr3M7ilMO-MRoSROP-W3h2EZem0KSEU-RAhM
> ```The computed code challenge is to be included in the authorization request
> in the next step, and the generated code verifier is to be included in the
> token request that will be made after the authorization request.
> ##### 4.3.2.3. Step 3 : Authorization Request
> Make an authorization request using the authorization code flow
> (cf. [RFC 6749, 4.1](https://www.rfc-editor.org/rfc/rfc6749.html#section-4.1)) by inputting the following URL in the
> address bar of your web browser. Don’t forget to replace `$` and
> `$` in the URL with the actual values of the issuer state and
> the code challenge you have created in the previous steps.
> ```
> https://trial.authlete.net/api/authorization?client_id=track1_light&response_type=code&issuer_state=$&redirect_uri=https://nextdev-api.authlete.net/api/mock/redirection&code_challenge=$&code_challenge_method=S256&prompt=login
> ```Accessing the URL will show you an authorization page. The page contains
> a login form. Input `inga` and `inga` into the Login ID field and the Password
> field in the login form, and press the “Authorize” button.
> [](/oid4vci)
> You will be redirected to the redirection endpoint (cf.
> [RFC 6749, 3.1.2](https://www.rfc-editor.org/rfc/rfc6749.html#section-3.1.2)).
> [](/oid4vci)
> This redirection endpoint displays key-value pairs that it has received.
> The value of the `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 `$` and `$` in the `curl` command
> below with the actual values you have obtained in the previous steps.
> ```shell
> curl -s https://trial.authlete.net/api/token \
> -d client_id=track1_light \
> -d grant_type=authorization_code \
> -d code=$ \
> -d redirect_uri=https://nextdev-api.authlete.net/api/mock/redirection \
> -d code_verifier=$
> ```If the token request is valid, the token endpoint returns JSON like below.
> ```json
```The value of the `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](https://github.com/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
`$` 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
`$` with the actual path of a file containing a private
key in the JWK format (cf. [RFC 7517](https://www.rfc-editor.org/rfc/rfc7517.html)). The file, `holder.jwk`, in
the [authlete/oid4vci-demo](https://github.com/authlete/oid4vci-demo) repository can be used
for the purpose.
```shell
git clone [email protected]:authlete/cbor.git
cd cbor
mvn compile
./bin/generate-cwt-key-proof \
--issuer https://trial.authlete.net \
--key $ \
--client track1_light \
--nonce $
```The `generate-cwt-key-proof` script will print a CWT key proof like below.
`
2D3ShFifowEmA3RvcGVuaWQ0dmNpLXByb29mK2N3dGhDT1NFX0tleVh7pgECAlgrMWU1QVk5RXlCMDFYblV6YTZMcEp6azAybjZZX0FtbW5TYjBGQmVOVlZyVQMmIAEhWCA9LFCsPbOXT-ZdwCrPWaCpJ4GgGGebHbLEESmsFjwXbSJYIMVfH24tRUqLFLpy3rizbi5CYqpmOkyojJ7q_hp9sEddoFhgpAFsdHJhY2sxX2xpZ2h0A3gaaHR0cHM6Ly90cmlhbC5hdXRobGV0ZS5uZXQGGmZf3KsKWCt2LTFiLW44MmtFSkdiSFJPU2VrR3NtUi14RXVhbUN4WV9UMHRYdFFOLWRZWEDVVsA-MQ9dAiaIRThTJ5JgmND4RZuhxcIiNx04TZ7fSqlQYJlRW9AyNqXeJHIEl1KqQs_yZtlPd98kRbvziTEi
`
The following is the result of decoding the CWT key proof above using [CBOR Zone](https://cbor.zone/).
```
61(18(/ COSE_Sign1 / [
/ protected
>>\`},
> / unprotected / ,
> h'a4016c747261636b315f6c6967687403781a68747470733a2f2f747269616c2e617574686c6574652e6e6574061a665fdcab0a582b762d31622d6e38326b454a476248524f53656b47736d522d784575616d4378595f5430745874514e2d6459',
> h'd556c03e310f5d02268845385327926098d0f8459ba1c5c222371d384d9edf4aa9506099515bd03236a5de2472049752aa42cff266d94f77df2445bbf3893122'
> ]))
> ```The value of `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 `$` and `$` in the
command line with the actual values.
```shell
curl -s https://trial.authlete.net/api/credential \
-H "Authorization: Bearer $" \
-H "Content-Type: application/json" \
--data ',
"given_name": ,
"birth_date": ,
"issue_date": ,
"expiry_date": ,
"issuing_country": ,
"document_number": ,
"driving_privileges":
\`}
},
"proof": '"
\`}
}'
```If the credential request is valid, the credential endpoint returns JSON
like below. The value of the `credential` property in the JSON is the
issued verifiable credential.
```json
```#### 4.3.3. Verifiable Credential Format
The CBOR Diagnostic Notation representation of the verifiable credential in
the previous section is as follows.
```
>>\`}),
> 24(
>>\`}),
> 24(
>>\`}),
> 24(
>>\`}),
> 24(
>>\`}),
> 24(
>>\`}),
> 24(
>>\`}),
> 24(
> ]
> \`}
>>\`})
> ]
> },
> "issuerAuth": [
> h'a10126',
> ,
> h'd8185902ada66776657273696f6e63312e306f646967657374416c676f726974686d675348412d3235366c76616c756544696765737473a1716f72672e69736f2e31383031332e352e31a80158206dc862912db60d0ad5e922a4a2c638b84587176f855fec80e842d6b841f456b0025820956b771416c1c7ea8858bbe72e51dd26a3f18a40f26899c667a840bfc9b41e7e0358209e85e9c4c808b20888afc1e527d2737da94448554b805c66112f52a9222c206d045820fee0ca3df12f2a83c489f11f8f30eee80875b7c1b7427d4f06192d271bb55a870558204f72bc22130bc33ca7bfa6d8ce00e4cc28917377a12f7bb8b9219360088fa191065820f0868f188ffb4e9dab7f67cb844ab4743ce6ef51664d950f735e81749b020e090758200a9d68c96939b0be0ab56289fc70bc0f68f4b5fa53845404a576bc5891e28b7308582045d54d51b12213fd47ae223c51ac7820ff69dc9f85865d0b0f9e38ef1c9118f36d6465766963654b6579496e666fa2696465766963654b6579a6010202582b3165354159394579423031586e557a61364c704a7a6b30326e36595f416d6d6e5362304642654e56567255032620012158203d2c50ac3db3974fe65dc02acf59a0a92781a018679b1db2c41129ac163c176d225820c55f1f6e2d454a8b14ba72deb8b36e2e4262aa663a4ca88c9eeafe1a7db0475d716b6579417574686f72697a6174696f6e73a16a6e616d6553706163657381716f72672e69736f2e31383031332e352e3167646f6354797065756f72672e69736f2e31383031332e352e312e6d444c6c76616c6964697479496e666fa3667369676e6564c074323032342d30362d30355430333a33353a31345a6976616c696446726f6dc074323032342d30362d30355430333a33353a31345a6a76616c6964556e74696cc074323032352d30362d30355430333a33353a31345a',
> h'0b3477430012b71a0356aea1d847c62bd872a8925dd416f4ab46f47a59a31a3fa043df91feff751426fd9f9f7e1667daa6cb4dcd8ea77c746b547e8227fd32d8'
> ]
> \`}
> ```
> 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](https://www.iso.org/standard/69084.html) as below.
> ```
> IssuerSigned =
> ```
> Unexpectedly, the OID4VCI specification does not specify which CBOR structure
> the value of 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.
> And, the `IssuerAuth` structure and some other relevant structures are defined
> as below.
> ```
> IssuerAuth = COSE_Sign1 ; The payload is MobileSecurityObjectBytes
> MobileSecurityObjectBytes = #6.24(bstr .cbor MobileSecurityObject)
> MobileSecurityObject =
> DeviceKeyInfo =
> DeviceKey = COSE_Key
> ```The definitions of `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.
> ```
> 24(
> },
> "deviceKeyInfo": ,
> "keyAuthorizations":
> },
> "docType": "org.iso.18013.5.1.mDL",
> "validityInfo":
> \`}
>>\`})
> ```
> 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)](https://www.iana.org/assignments/cose/cose.xhtml) for the
meanings of the integer labels and integer values in the COSE Key.
### 4.4. POTENTIAL Interop Event / Track 2 / Light Profile
[POTENTIAL](https://www.digital-identity-wallet.eu/) 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
| Parameter | Value |
| --- | --- |
| Issuer Identifier | `https://trial.authlete.net` |
| Authorization Endpoint | `https://trial.authlete.net/api/authorization` |
| Token Endpoint | `https://trial.authlete.net/api/token` |
| Discovery Endpoint | `[https://trial.authlete.net/.well-known/openid-configuration](https://trial.authlete.net/.well-known/openid-configuration)` |
| Entity Configuration | `[https://trial.authlete.net/.well-known/openid-federation](https://trial.authlete.net/.well-known/openid-federation)` |
The source code of the authorization server is available at
[https://github.com/authlete/java-oauth-server](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
| Parameter | Value |
| --- | --- |
| Issuer Identifier | `https://trial.authlete.net` |
| Credential Endpoint | `https://trial.authlete.net/api/credential` |
| Metadata Endpoint | `[https://trial.authlete.net/.well-known/openid-credential-issuer](https://trial.authlete.net/.well-known/openid-credential-issuer)` |
| Entity Configuration | `[https://trial.authlete.net/.well-known/openid-federation](https://trial.authlete.net/.well-known/openid-federation)` |
The source code of the credential issuer is the same as that of the
authorization server.
##### 4.4.1.3. Client Settings
| Parameter | Value |
| --- | --- |
| Client ID | `track2_light` |
| Client Type | public (= [client authentication](https://medium.com/@darutk/oauth-2-0-client-authentication-4b5f929305d4) is not required) |
| Redirect URIs | `https://nextdev-api.authlete.net/api/mock/redirection``eudi-openid4ci://authorize/` |
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](https://www.authlete.com/contact/).
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](https://www.rfc-editor.org/rfc/rfc7636.html)) by using the `pkce` command
```shell
git clone [email protected]:authlete/oid4vci-demo.git
cd oid4vci-demo
./pkce
```The `pkce` command will print a generated code verifier and the computed code
challenge like below.
```shell
CODE_VERIFIER=gzRNlV7DLS_HyKMQKQMrzgYQ8aY3H2rVJ3iIlYK0cjE
CODE_CHALLENGE=j_4gpG9Kr3M7ilMO-MRoSROP-W3h2EZem0KSEU-RAhM
```The computed code challenge is to be included in the authorization request
in the next step, and the generated code verifier is to be included in the
token request that will be made after the authorization request.
##### 4.4.2.2. Step 2 : Authorization Request
Make an authorization request using the authorization code flow
(cf. [RFC 6749, 4.1](https://www.rfc-editor.org/rfc/rfc6749.html#section-4.1)) by inputting the following URL in the
address bar of your web browser. Don’t forget to replace `$`
in the URL with the actual value of the code challenge you have created in
the previous step.
```
https://trial.authlete.net/api/authorization?client_id=track2_light&response_type=code&scope=potential.track2.light.profile&redirect_uri=https://nextdev-api.authlete.net/api/mock/redirection&code_challenge=$&code_challenge_method=S256&prompt=login
```Accessing the URL will show you an authorization page. The page contains
a login form. Input `inga` and `inga` into the Login ID field and the Password
field in the login form, and press the “Authorize” button.
[](/oid4vci)
You will be redirected to the redirection endpoint (cf.
[RFC 6749, 3.1.2](https://www.rfc-editor.org/rfc/rfc6749.html#section-3.1.2)).
[](/oid4vci)
This redirection endpoint displays key-value pairs that it has received.
The value of the `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 `$` and `$` in the `curl` command
below with the actual values you have obtained in the previous steps.
```shell
curl -s https://trial.authlete.net/api/token \
-d client_id=track2_light \
-d grant_type=authorization_code \
-d code=$ \
-d redirect_uri=https://nextdev-api.authlete.net/api/mock/redirection \
-d code_verifier=$
```If the token request is valid, the token endpoint returns JSON like below.
```json
```The value of the `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 key `holder.jwk` and the `generate-key-proof` script.
The JWK file and the script are contained in the [oid4vci-demo repository](https://github.com/authlete/oid4vci-demo).
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.
```shell
./generate-key-proof \
-i https://trial.authlete.net \
-k holder.jwk \
-c track2_light \
-n $C_NONCE
```The `generate-key-proof` script will generate a JWT Key Proof like below.
`
eyJ0eXAiOiJvcGVuaWQ0dmNpLXByb29mK2p3dCIsImFsZyI6IkVTMjU2IiwiandrIjp7ImNydiI6IlAtMjU2Iiwia3R5IjoiRUMiLCJ4IjoiUFN4UXJEMnpsMF9tWGNBcXoxbWdxU2VCb0Jobm14Mnl4QkVwckJZOEYyMCIsInkiOiJ4VjhmYmkxRlNvc1V1bkxldUxOdUxrSmlxbVk2VEtpTW51ci1HbjJ3UjEwIn19.eyJpc3MiOiJ0cmFjazJfbGlnaHQiLCJhdWQiOiJodHRwczovL3RyaWFsLmF1dGhsZXRlLm5ldCIsImlhdCI6MTcxNzYxNzk1Nywibm9uY2UiOiJydnczTW9fWkh5RWdZT29XUTlHRW90ZW13RmJoUnZWVmRJNmU1WjBsaEVzIn0.E-9pdaSW2oaFqI2V0N1aRiSRI3LzOxwQFNR5tewaLXxP8R7ZHrU9-M7TLuqP5OmWRecdFrJ9yQAM83kbc4f5-A`
Decoding the header and the payload of the JWT Key Proof by base64url will show the following JSONs.
```json
\`}
``````json
```The result of executing the `generate-key-proof` script can be directly set to
the shell variable `JWT_KEY_PROOF` by doing the following.
```shell
JWT_KEY_PROOF=`./generate-key-proof -i https://trial.authlete.net -k holder.jwk -c track2_light -n $C_NONCE`
```
##### 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 `$` and `$` in the
command line with the actual values.
```shell
curl -s https://trial.authlete.net/api/credential \
-H "Authorization: Bearer $" \
-H "Content-Type: application/json" \
--data ''"
\`}
}'
```If the credential request is valid, the credential endpoint returns JSON
like below. The value of the `credential` property in the JSON is the
issued verifiable credential.
```json
```#### 4.4.3. Verifiable Credential Format
The value of the `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.
```shell
./decode-sd-jwt $SD_JWT
```The result will look like below.
```json
,
"_sd": [
"1A8fFbJ1Ya3tfCvDQzK4sLIHLDRDEbDbMhPEfp_SG5U",
"28jL7wHUtq0n1wZAJfcWhL5NZKyBkL0TU3siiSOlezY",
"2cr_E536qMQ00wgPS1D_lvreAasmmspxaNvOQ_wvmLA",
"5uq6z-wAhZeBD2KwV1N5NeqDjIjWTzjB-1UOujvNRYY",
"6waVTKzVi1fh1LPsF_mDJubkraadjgPKXMGI7PznV0g",
"78rctRsmEanWZ2nvOTWr5YoXFyyntfIq1MN8jumrB8o",
"88vwsUUlr5FabPhO5XacwHtngMuSv4DVa_kA99E1kys",
"9GzaN1eg56W3TCxhlp9fKSOwHS_nhDxF1VrSlH7gq1E",
"BwZFQTCjVM1EnHsUHyt3grcthV2RHVqdLbTv3--Ek8g",
"Ed7UlXXKK2uwlnRMtzRdtg8T0mWnQxA9UNnPetKuOuc",
"FNzxWfHda7HWpGdAjI3TwZxWxNXGLp4wjpGu_CjGAXc",
"GnIFF8X9NZBmTJCa99LxPQROG5c6XQk2zbu4ocln9Ik",
"LsflpqTLX8OJXbNwy7qp570tJcB9OGPxOjMLDSmAQ2I",
"dsJV0Ggb_fUcxiOjToUIChJFGQyhRLdzvYimBceI3zc",
"h2vSwQStI_KpkqSWc7MuLn8VPykEczREZ3DgXTwt33Q",
"jCIxgIdcbNRuCmBCx_CAT0gaoeDBSoUByx_7_DU1Bdo",
"kteHiYvX_mjaGK4bE8b62FKgRvvlTBMSq-xiVRPe0zQ",
"pyurk5OsxkXKahgidmwkMNz50TikF-_3FF4XoRbX4l4",
"vTw9VZR8ZMAm3ZHqdbq5PqIPAgC6mYrXaxbadzAP8jY"
],
"address": ,
"vct": "urn:eu.europa.ec.eudi:pid:1",
"_sd_alg": "sha-256",
"iss": "https://trial.authlete.net",
"cnf":
\`},
"iat": 1717618661,
"age_equal_or_over":
\`}
```
### 4.5. POTENTIAL Interop Event / Track 2 / Full Profile
[POTENTIAL](https://www.digital-identity-wallet.eu/) 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
| Parameter | Value |
| --- | --- |
| Issuer Identifier | `https://trial.authlete.net` |
| Authorization Endpoint | `https://trial.authlete.net/api/authorization` |
| Token Endpoint | `https://trial.authlete.net/api/token` |
| PAR Endpoint | `https://trial.authlete.net/api/par` |
| Discovery Endpoint | `[https://trial.authlete.net/.well-known/openid-configuration](https://trial.authlete.net/.well-known/openid-configuration)` |
| Entity Configuration | `[https://trial.authlete.net/.well-known/openid-federation](https://trial.authlete.net/.well-known/openid-federation)` |
The source code of the authorization server is available at
[https://github.com/authlete/java-oauth-server](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
| Parameter | Value |
| --- | --- |
| Issuer Identifier | `https://trial.authlete.net` |
| Credential Endpoint | `https://trial.authlete.net/api/credential` |
| Metadata Endpoint | `[https://trial.authlete.net/.well-known/openid-credential-issuer](https://trial.authlete.net/.well-known/openid-credential-issuer)` |
| Entity Configuration | `[https://trial.authlete.net/.well-known/openid-federation](https://trial.authlete.net/.well-known/openid-federation)` |
The source code of the credential issuer is the same as that of the
authorization server.
##### 4.5.1.3. Client Settings
| Parameter | Value |
| --- | --- |
| Client ID | `track2_full` |
| Client Type | confidential |
| Client Authentication Method | `attest_jwt_client_auth` |
| Redirect URIs | `https://nextdev-api.authlete.net/api/mock/redirection``eudi-openid4ci://authorize/` |
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](https://www.authlete.com/contact/).
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](https://www.rfc-editor.org/rfc/rfc7636.html)) by using the `pkce` command
```shell
git clone [email protected]:authlete/oid4vci-demo.git
cd oid4vci-demo
./pkce
```The `pkce` command will print a generated code verifier and the computed code
challenge like below.
```shell
CODE_VERIFIER=gzRNlV7DLS_HyKMQKQMrzgYQ8aY3H2rVJ3iIlYK0cjE
CODE_CHALLENGE=j_4gpG9Kr3M7ilMO-MRoSROP-W3h2EZem0KSEU-RAhM
```The computed code challenge is to be included in the PAR request
([RFC 9126](https://www.rfc-editor.org/rfc/rfc9126.html)), and the generated code verifier is to be included in
the token request, which will be made later.
##### 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](https://datatracker.ietf.org/doc/draft-ietf-oauth-attestation-based-client-auth/)”
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](https://github.com/authlete/oid4vci-demo) repository includes two scripts,
`generate-client-attestation` and
`generate-client-attestation-pop`, for generating
the JWTs. Their usage is as follows:
```
Usage: generate-client-attestation [options]
--attester-id=ATTESTER_ID The identifier of the client attestation issuer.
--attester-key=FILE The file containing the private key of the client attestation issuer in the JWK format.
--client-id=CLIENT_ID The identifier of the client application.
--client-key=FILE The file containing the public key of the client application in the JWK format.
--duration=DURATION The duration of the client attestation in seconds. The default value is 86400.