Client
OpenID for Verifiable Credential Issuance - Client
Background
A client to request and receive Verifiable Credentials using the OpenID for Verifiable Credential Issuance ( OpenID4VCI) specification for receiving Verifiable Credentials as a holder/subject.
OpenID4VCI defines an API designated as Credential Endpoint that is used to issue verifiable credentials and corresponding OAuth 2.0 based authorization mechanisms (see [RFC6749]) that a Wallet uses to obtain authorization to receive verifiable credentials. W3C formats as well as other Credential formats are supported. This allows existing OAuth 2.0 deployments and OpenID Connect OPs (see [OpenID.Core]) to extend their service and become Credential Issuers. It also allows new applications built using Verifiable Credentials to utilize OAuth 2.0 as integration and interoperability layer. This package provides holder/wallet support to interact with OpenID4VCI capable Issuer systems.
Flows
The spec lists 2 flows. Currently only one is supported!
Authorized Code Flow
This flow isn’t supported yet!
Pre-authorized Code Flow
The pre-authorized code flow assumes the user is using an out-of-band mechanism outside the issuance flow to authenticate first.
The below diagram shows the steps involved in the pre-authorized code flow. Note that wallet inner functionalities (like saving VCs) are out of scope for this library.
Initiating the client
This initiates the client using a URI obtained from the Issuer using a link (URL) or QR code typically. We are also already fetching the Server Metadata
Using https scheme
Server metadata
The OID4VCI Server metadata contains information about token endpoints, credential endpoints, as well as additional
information about supported Credentials, and their cryptographic suites and formats.
The code above already retrieved the metadata, so it will not be fetched again, and this method places the data in another variable. If you however have not used
the retrieveServerMetadata
option, you can use this method to fetch it from the Issuer:
Access token from Authorization Server
Next we need to get an Access token from the OAuth2 Authorization Server using the token endpoint. This endpoint is found from the metadata if the server supports it. Otherwise a default location based on the issuer value from the Initiate Issuance Request is used.
Getting the credential
Now it is time to get the credential. In order to achieve this, we will be using the metadata together with the access token, but first we will have to create a so-called Proof of Possession. Please see the Proof of Posession chapter for more information.
The Proof of Possession using a signature callback function. The example uses the jose
library.
Now it is time to get the actual credential
Using individual classes and methods instead of the client
Instead of using the OpenID4VCI Client, you can also use the separate classes if you want. This typically gives you a bit more control and options, at the expense of a bit more complexity.
Issuance Initiation
Issuance is started from a so-called Issuance Initiation Request by the Issuer. This typically is URI, exposed
as a link or a QR code. You can call the CredentialOffer.fromURI(uri)
method to parse the URI into a Json object
containing the baseUrl and a uri
JSON object
Getting OpenID4VCI Server and OIDC/OAuth2 metadata
The OpenID4VCI spec defines a server metadata object that contains information about the issuer and the credentials they support. Next to this predefined endpoint there are also the well-known locations for OpenID Connect Discovery configuration and Oauth2 Authorization Server configuration. These contain for instance the token endpoints. The MetadataClientV1_0_13 checks the OpenID4VCI well-known location for the medata and existence of a token endpoint. If the OpenID4VCI well-known location is not found, the OIDC/OAuth2 well-known locations will be tried:
Example:
Acquiring the Access Token
Now you will need to get an access token from the oAuth2 Authorization Server (AS), using some values from
the IssuanceInitiationRequestPayloadV9
payload.
For now, you can use the issuer hostname for the AS, as there is no way to know the AS from the Issuance Initiation for
known until the
following OpenID Ticket is
resolved. So the token endpoint would become https://<issuer-hostname>/token.
The library allows to pass in a different value for the AS token endpoint as well, so you already can use a different AS
if you know the AS upfront. If no AS is provided the issuer value from the Issuance Initiation Request will be used.
Proof of Possession
Part of OpenID4VCI is the holder showing that they are in possession of a certain key, associated with the DID that will
be the subject of the to be issued Verifiable Credential.
This proof of possession will be created using a DID, it’s associated keypair and the ProofOfPossessionBuilder
class.
This Builder can be initiated from a JWT object if you want to create a JWT yourself, or it can be build using the
Initiate Issuance Request, Server metadata and some methods from the builder. Both approaches need a callback function
to sign the JWT and optionally a callback to verify the JWT.
The signature of the callback functions you need to implement are:
This is an example of the signature callback function created using the jose
library.
Alongside signing, you can optionally provide another callback function for verifying the created signature with
populating verifyCallback
. The method is expected to throw errors in case problems with the JWT or it’s signature are
found.
below is an example of such method. This example (like the previous one) uses jose
to verify the jwt.
Some important interface around Proof of Possession:
The arguments requested by jose
and @sphereon/oid4vci-client
Using the builder from metadata and access token response
Normally you would use the Proof of Possession builder using the server metadata and access token response together with the callbacks. There is however the possibility to use a JWT directly, which will be explained in the next section.
Using the builder with a self-created JWT
You can build/create a JWT yourself. You would still use the callbacks to sign the JWT. Please be aware that you will
have to use the c_nonce
value from the Access Token response as nonce
value!. You can provide another nonce using
the jti
property.
Credential Issuance
Now it is time to request the actual Credential(s) from the Issuer. The example uses a DID:JWK. The DID:JWK should match the keypair created earlier.
Helper Functions
Several utility functions are available
convertJsonToURI:
Converts a Json object or string into an URI:
convertURIToJsonObject:
Converts a URI into a Json object with URL decoded properties. Allows to provide which potential duplicate keys need to be converted into an array.