Skip to main content

Receive a credential

Learn how to receive a credential.

Whether using server-based wallet or a mobile app, the system supports the following flows for OpenID4VCI:

  • Pre-authorized Code Flow
  • Authorization Code Flow
    • Wallet-initiated

This page provides implementation details and explains how to complete each flow when using the system as a credential holder. For a description of the flows at a conceptual level, see OID4VCI flows explained.

Implementation

When used as a credential holder, the system supports the following features.

PKCE

info

The system uses PKCE with authorization servers that support it.

Proof Key for Code Exchange, or PKCE (pronounced "pixy"), is an extension of the Authorization Code Grant to mitigate the threat of an attacker intercepting an authorization code.

The client generates a cryptographically random code verifier and derives a code challenge from it, which is sent to the authorization server during the initial authorization request. When exchanging the authorization code for tokens, the client must provide the original code verifier, allowing the authorization server to verify that the same client that initiated the flow is completing it.

PKCE RFC

PAR

info

The system uses PAR with authorization servers that support it.

Pushed Authorization Request, or PAR, is an OAuth 2.0 extension that allows clients to push authorization request parameters directly to the authorization server's PAR endpoint before initiating the authorization flow.

The client sends all authorization parameters (including sensitive data like scope, state, and code challenge) via a secure back-channel POST request, receiving a request URI in return. This request URI is then used in place of the authorization parameters when redirecting the user to the authorization server, reducing the risk of parameter tampering and exposure through browser history or referrer headers.

PAR RFC

Flows in the system

info

The following sections describe each flow from the perspective of the actions the wallet takes. Each action is then described in its own section below. Click an action to go directly to its description.

Pre-Authorized Code Flow

This flow is initiated by the issuer through a shared QR code or URL. Pass this URL directly to the "Handle invitation" endpoint to start the flow. From there the offered credential can be fetched and reviewed.

Authorization Code Flow initiated by wallet

Initiate this flow by passing a credential request, including issuer and credential metadata, to the "Initiate issuance" endpoint. The issuer responds with a redirect URL, pointing the end user to the authorization process. When that process is complete, the authorization server returns a new URL; pass this URL to the "Continue issuance" endpoint, after which you can fetch the offered credential for review.

Authorization Code Flow initiated by issuer

info

To enable this flow, the issuer and client ID must be specified in the configuration.

Initiate this flow by calling the "Handle invitation" endpoint, passing both the issuer's credential offer URL and the redirect URI – where the authorization server should return to within the wallet after completion of authentication. The system returns the Authorization Code Flow URL used to start the process with the server.

When the user is redirected back to the wallet, the URL given to the user by the authorization server is passed to the "Continue issuance" endpoint, and the system makes its request for an access token.

Initiate issuance

For wallet-initiated flows, use this endpoint to make the initial request for credential issuance. This endpoint requires authorization request parameters.

The following is an example call:

curl -L -X POST '/api/interaction/v1/initiate-issuance' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer <TOKEN>' \
-d '{
"protocol": "OpenID4VCI", // From your configuration
"issuer": "https://example.com", // Issuer URL
"clientId": "openid-client", // Wallet's client ID
"redirectUri": "https://example.com", // Optional
"scope": [ // Either provide the scope, OR
"bli",
"blu"
],
"authorizationDetails": [ // Provide the authorizationDetails
{
"type": "openid_credential",
"credentialConfigurationId": "UniversityDegreeCredential"
}
]
}'

The issuer responds with the authorization endpoint URL; the end user can follow this to complete the authorization process with the authorization server.

Continue issuance

After completing the authorization process, the authorization server returns a URL. Pass this URL to this endpoint to continue the issuance flow.

curl -L -X POST '/api/interaction/v1/continue-issuance' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer <TOKEN>' \
-d '{
"url": "https://example.com/authorized"
}'

The system responds with:

  • interactionId: for reference
  • credentialIds: array of IDs representing the offered credentials
  • credentialConfigurationsSupported: informs client of API about valid options for issuance including applicable signing algorithms

This response provides everything needed to review an offered credential and accept or reject the offer.

Handle invitation

The issuer will share an invitation URL, often encoded as a QR code. The URL is generated from the issuance protocol; your system must support the issuance protocol used to be able to parse the offer correctly.

Use the "Handle invitation" endpoint to parse the invitation URL.:

curl -L -X POST '/api/interaction/v1/handle-invitation' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer <TOKEN>' \
-d '{
"url": "https://example.com/invitation"
}'

This endpoint takes an invitation URL from the issuer and retrieves the offer, returning two things:

  • Interaction ID: this is a reference for the newly created interaction. You will use this ID when you later respond to the offer.
  • Credential IDs: this is an array of IDs representing the offered credentials. You can look up details of the offered credentials but they are not yet issued to the wallet.

Transport array

If you have multiple transport protocols configured you can use this array to override the default protocol. For wallets, this is generally only the case for mobile devices.

Get credential

To see the offer, look up the credential:

curl -L '/api/credential/v1/{credentialId}' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer <TOKEN>' \

Respond to offer

Review the offered credential and either accept it or reject it.

Accept offer

Choose an identifier to use to accept the credential — the identifier becomes part of the issued credential and will need to be used again when you present the credential to a verifier.

Choosing an identifier

Check the following capabilities for a report of which identifiers and associated key algorithms can be used with the format of the credential you want to accept:

  • holderIdentifierTypes
  • holderKeyAlgorithms
  • holderDidMethods
curl -L -X POST '/api/interaction/v1/issuance-accept' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer <TOKEN>' \
-d '{
"identifierId":"{{CHOOSE-IDENTIFIER}}",
"interactionId":"{{FROM-HANDLE-INVITATION}}"
}'

Reject offer

curl -L -X POST '/api/interaction/v1/issuance-reject' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer <TOKEN>' \
-d '{
"interactionId":"{{FROM-HANDLE-INVITATION}}"
}'