OpenID4VCI
OpenID for Verifiable Credential Issuance (OpenID4VCI) defines how an issuer offers credentials to a wallet and how the wallet retrieves them.
This page explains how to configure OpenID4VCI for issuing credentials.
- To configure a wallet to receive credentials, see OpenID4VCI and OpenID4VP for wallets
- For every supported parameter, see the configuration reference
Enable OpenID4VCI
To issue with OpenID4VCI, configure at least one enabled instance in the
issuanceProtocol object. The system supports one type:
OPENID4VCI_FINAL1: OpenID for Verifiable Credential Issuance 1.0
You can configure more than one instance of the same type, each with its own settings. When you create a credential, you choose which instance to issue it with. See URL scheme for a common reason to do this.
Example configuration
issuanceProtocol:
OPENID4VCI_FINAL1:
display: "exchange.openIdFinal1"
order: 1
type: "OPENID4VCI_FINAL1"
params:
public:
preAuthorizedCodeExpiresInSeconds: 300
tokenExpiresInSeconds: 86400
refreshExpiresInSeconds: 7776000
redirectUri:
enabled: true
allowedSchemes: ["https"]
webhookTask: "WEBHOOK1"
dpop:
enforced: true
nonceValiditySeconds: 300
leewaySeconds: 60
signingAlgorithms: ["ECDSA", "EDDSA"]
private:
encryption: "<32-byte hex>"
nonce:
signingKey: "<32-byte hex>"
expirationSeconds: 300
leewaySeconds: 60
dpop:
signingKey: "<32-byte hex>"
The sections below explain each part of this configuration.
Keys
Each OpenID4VCI instance needs its own keys:
nonce.signingKey: Signs the nonces the issuer generates during issuance. Required.encryption: Encrypts the access and refresh tokens Core receives from issuers when it holds credentials as a wallet. Required for every instance, even if you only use Core to issue.dpop.signingKey: Signs the nonces used in DPoP flows. Required ifdpop.enforcedistrue. See DPoP.
Keys are 32-byte hex strings. Supply them as environment variables rather than in configuration files. See Secrets and Keys for how to generate and supply keys, and what happens when you rotate them.
Nonces
OpenID4VCI uses nonces to make sure each credential request is fresh, which prevents replay attacks. Alongside the signing key, configure:
nonce.expirationSeconds: How long a nonce remains valid.nonce.leewaySeconds: Time tolerance when validating nonce timestamps, to allow for clock differences between systems.
Code and token lifetimes
These parameters control how long the codes and tokens in an issuance flow remain valid:
preAuthorizedCodeExpiresInSeconds: How long a pre-authorized code can be exchanged for an access token. Make this long enough for holders to complete their wallet interaction, but short enough to limit the risk of a leaked offer being used.tokenExpiresInSeconds: How long an access token can be used to retrieve credentials. Allow for network latency, retries, and how long your holders typically take.refreshExpiresInSeconds: How long a refresh token remains valid. As long as the wallet uses its refresh token before it expires, the wallet can obtain new access tokens and refresh a batch of credentials without repeating the full issuance flow, provided the credentials have not been suspended or revoked. Choose this value with security in mind: a stolen refresh token can be used until it expires. With DPoP, refresh tokens are bound to the wallet's key, which reduces this risk because a stolen refresh token cannot be used without that key.
The validity period of the credentials themselves is set elsewhere. See Credential Expiration for Issuers.
DPoP
Demonstrating Proof of Possession (DPoP) binds the tokens you issue to a key held by the wallet. A wallet must prove possession of that key each time it uses a token, so a stolen access or refresh token cannot be used by anyone else.
To enable DPoP, include a dpop block in the instance's parameters. If
the block is absent, DPoP is not offered to wallets.
Required or optional
Use dpop.enforced to choose whether wallets must use DPoP:
true(default): DPoP is required. Wallets that do not support DPoP cannot complete issuance.false: DPoP is offered to wallets as an additional security feature, but not required. Wallets that do not support it can still receive credentials. A wallet that chooses to use DPoP must keep using it for every future refresh of the issuance.
For example, to offer DPoP without requiring it:
params:
public:
dpop:
enforced: false
signingAlgorithms: ["ECDSA", "EDDSA"]
private:
dpop:
signingKey: "<32-byte hex>"
Parameters
dpop.signingKey: 32-byte hex key used to sign DPoP nonces. Required whenever thedpopblock is present. See Secrets and Keys: Generating Values.dpop.signingAlgorithms: The key algorithms wallets can use for their DPoP key. Required whenever thedpopblock is present. Use any enabled key algorithm, by configuration instance name.dpop.nonceValiditySeconds: How long a DPoP nonce remains valid. Defaults to 300 seconds.dpop.nonceRefreshThresholdSeconds: When a wallet submits a valid nonce that expires within this many seconds, the issuer provides a new nonce for the wallet to use. Defaults to 60 seconds.dpop.leewaySeconds: Time tolerance when validating DPoP nonce timestamps.
Redirect URIs
You can redirect holders to a URI after they accept your credential
offer. To allow this, set redirectUri.enabled to true and list the
URI schemes you accept in redirectUri.allowedSchemes, for example
https or myapp. If no schemes are listed, all redirect URIs are
rejected.
You then set the redirect URI for each credential when you create it.
URL scheme
The URL scheme of a credential offer tells wallets how to handle it.
Offers use the openid-credential-offer scheme by default, as specified
in the OpenID4VCI standard. To use a different scheme, set the
urlScheme parameter. Any scheme can be used, as long as the wallets you
issue to recognize it.
To support more than one scheme at the same time, configure one instance for each scheme. When you create a credential, reference the instance whose scheme you want to use.
HAIP
The OpenID4VC High Assurance Interoperability Profile
(HAIP)
defines the haip-vci scheme for credential offers. HAIP is the basis for
interoperability in ecosystems such as the EUDI Wallet ecosystem.
issuanceProtocol:
OPENID4VCI_FINAL1_HAIP:
display: "exchange.openIdFinal1Haip"
order: 2
type: "OPENID4VCI_FINAL1"
params:
public:
urlScheme: haip-vci
Setting urlScheme to haip-vci does not make an instance
HAIP-compliant, and the system does not check the rest of the instance's
configuration against HAIP. Configure the instance to meet HAIP's
requirements yourself. For example, HAIP requires DPoP support; see
DPoP.
Webhooks
To send notifications for issuance events, set webhookTask to a
configured WEBHOOK_NOTIFY task. See Webhooks.