What you'll learn
- Parse and process credential offer URLs in OID4VCI format
- Accept credential offers via the Wallet API endpoint
- Display credential details to users before acceptance
- Handle credential offers from QR codes, links, or manual input
Learn how to accept W3C verifiable credentials (JWT/SD-JWT) via OID4VCI in a wallet using walt.id's Wallet API, including parsing credential offer URLs and displaying credentials to users.
What you'll learn
Relevant concepts
There are several methods by which a user can receive a credential into their wallet, and all are supported by the walt.id wallet API:
Irrespective of the chosen method, these are just different ways of receiving, parsing and fulfilling a request URL.
A credential offer URL is a standardized method, as per the OID4VCI specification, to communicate the issuance of
credentials between issuer and wallet. This URL can take various forms, such as a QR code or a link, and generally
begins with openid-credential-offer://.
Example Offer URL
openid-credential-offer://issuer.portal.walt.id/?credential_offer=<credential_offer>
Within the URL, a query parameter credential_offer provides the actual offer as a JSON object.
Example of a Credential Offer Object
{
"credential_issuer": "https://issuer.demo.walt.id",
// This is the URL of the issuer of the credential(s)
"credentials": [
// This array contains details about the types of credentials being offered
{
"format": "jwt_vc_json",
// Specifies the format of the credential
"types": [
// An array indicating the credential types
"VerifiableCredential",
"BankId"
],
"credential_definition": {
"@context": [
// Provides the contexts of the credential
"https://www.w3.org/2018/credentials/v1"
],
"types": [
// Reiterates the type of credential being offered.
"VerifiableCredential",
"BankId"
]
}
}
],
"grants": {
// Specifies how the credentials can be obtained
"authorization_code": {
"issuer_state": "<issuer_state>"
// Contains an issuer_state, a unique identifier for the grant
},
"urn:ietf:params:oauth:grant-type:pre-authorized_code": {
// Provides details for a pre-authorized code grant type,
//including the actual pre-authorized_code and a flag user_pin_required indicating whether a PIN is required
// for user authentication.
"pre-authorized_code": "<pre-authorized_code>",
"user_pin_required": false
}
}
}
To accept a credential via the credential offer URL:
See an example below.
Accepting the offer
To accept the offer via the Wallet API:
/wallet-api/wallet/{wallet}/exchange/useOfferRequest endpoint.did and the walletId as request parameters.Example Call | Api Reference
curl -X 'POST' \
'http://0.0.0.0:7001/wallet-api/wallet/{wallet}/exchange/useOfferRequest?did=did%3Akey%3Az6MknMppUdsg34t6oPevGDijgB9w9862Ai6Xu5iexjNU2Uoh' \
-H 'accept: */*' \
-H 'Content-Type: text/plain' \
-d 'openid-credential-offer://issuer.portal.walt.id/?credential_offer=<credential_offer>'
You can receive the needed wallet id parameter via the /wallet-api/wallet/accounts/wallets endpoint.
Example Display Of Credentials To User
In JavaScript, assuming that you already have the offer URL and a function decodeOfferURL(offerURL) that returns the JSON offer object, you might do it like this:
// Assuming we have the offer URL
var offerURL = "openid-credential-offer://...";
// Extract Offer object from the URL
var offerObject = decodeOfferURL(offerURL);
// Iterate through credentials within the offer object and present to the user
var credentialDetails = offerObject["credentials"].map((credential) => {
var lastType = credential.types[credential.types.length - 1]; // Get last type
return {
format: credential.format,
type: lastType,
};
});
// Display credential details
credentialDetails.forEach((credential) => {
console.log(`Format: ${credential.format}`);
console.log(`Type: ${credential.type}`);
});
The user would then see a list of credentials that would be received, and they could confirm whether they want to proceed with accepting the offer.
Note that the above code is a simple example and assumes that decodeOfferURL(offerURL) exists. In a real application, you would likely use a library to perform URL parsing and JSON decoding, and handle any errors appropriately.
On this page