#How to Verify an SD-JWT-based Verifiable Credential (IETF | SD-JWT VC) via OID4VP with walt.id
TL;DR
Learn how to verify SD-JWT-based Verifiable Credentials (IETF SD-JWT VC) via OID4VP using walt.id's verifier API, including policy configuration, custom presentation definitions, and result retrieval.
What you'll learn
Create verification requests for SD-JWT VC credentials via OID4VP
Configure VC and VP policies for credential verification
Implement custom presentation definitions with field constraints
Retrieve and inspect verification results and presented credentials
Relevant concepts
SD-JWT VC – Intro to the IETF standard for selective disclosure credentials
OpenID4VP – Protocol for requesting and receiving verifiable presentations
This guide provides a comprehensive walkthrough for verifying a SD-JWT VC credentials based on
the IETF standard using
the walt.id verifier API. The verification process will utilize the OID4VCI protocol, an extension of OpenID,
facilitating secure and standardized communication between identities.
SD-JWT VC: A digital equivalent of physical credentials such as a driver's license or university
degree. VCs are cryptographically secure, privacy-respecting, and instantly verifiable.
OID4VCI: A protocol specifying how parties can issue VCs and present these credentials in a way that's consistent
and secure across platforms ensuring interoperability.
First, determine the type of SD-JWT VC Credential to be verified. Although this guide focuses on a "VerifiableDiploma,"
you can use any credential type compliant with the IETF standard.
The verification process will be as follows:
Specify the credential type(s) to request from a user and the verification policies to be applied to the credential(
s).
Optionally provide a success and failure redirect URL, which the user will be redirected to after the verification
process is completed.
API returns a URL which can passed to OIDC-compliant wallet to fulfill the request.
If you have provided a success or failure redirect URL, the user will be redirected to that URL. You can then access the
verification results by using the id of the verification session, which can be found in the URL generated by the API, as
well as in the query or path parameters of the redirect URL.
authorizeBaseUrl - is used to modify the start of the OID4VC request URL. The default value is openid4vp://authorize which
is fine for most use-cases. If you however are required to use the HAIP OID4VC profile, you need to update the value as follows: haip://
responseMode - should be direct_post as the other options are not yet supported.
successRedirectUri (optional) - is used to redirect the user if verification is successful. You can use the $id
placeholder
to get access to the id of verification session in your application in order to retrieve the verification results.
E.g. /success?id=$id will be replaced with /success?id=1234567890
errorRedirectUri (optional) - is used to redirect the user if verification is unsuccessful. You can use the $id
placeholder
to get access to the id of verification session in your application in order to retrieve the verification results.
E.g. /error?id=$id will be replaced with /error?id=1234567890
statusCallbackUri (optional) - URL that should be called when the presentation request has been fulfilled by a
wallet. The request
sent will be a POST including the whole presentation
result. See Verification Status Policies Response
statusCallbackApiKey (optional) - If the endpoint you provide via statusCallbackUri is protected, you can use
the statusCallbackApiKey to authenticate.
The provided key will be appended as Authorization Header to the request.
stateId (optional) - overwrite the unique state value which gets created for each verification request with your
own.
openId4VPProfile (optional) - Define profile for VP (Verifiable Presentation) request. The default is W3C
OpenID4VP, which can optionally provided as DEFAULT.
Apart from that, you can choose from the following options:
HAIP: For the OID4VC HAIP profile.
EBSIV3: For EBSI V3 compliant VP. Learn more here.
ISO_18013_7_MDOC: For mdoc Openid4VP.
Body Parameters
vp_policies - Policies applied to the Verifiable Presentation. A list of policies can be
found here
vc_policies - Policies applied to all requested credentials. A list of policies can be
found here.
request_credentials - An array of objects detailing the credentials to be requested from the user. Each object
varies based on the type of credential being requested.
Expand To Learn More
Below are the possible credential types and their respective object structures:
format: Describes the format of the credential. For SD-JWT VC credentials, this would be
vc+sd-jwt.: Describes the format of the credential. For SD-JWT VC credentials, this would be vc+sd-jwt.
Please note that if you are using the HAIP profile, you cannot specify custom policies at this point.
In this example, we not only specify the types of credentials to verify, but also define the policies that should be
executed during verification:
VC policies (vc_policies): Applied to individual Verifiable Credentials (VCs).
VP policies (vp_policies): Applied to the Verifiable Presentation (VP) as a whole.
Default behavior: The signature policy is applied by default to both VP and VC(s).
Policy catalog: A list of available policies can be found
here.
How VC policies are applied:
Global scope: Once defined, VC policies are applied globally to all requested credentials in the verification
session.
Per-credential override: A later section shows how to customize and apply specific policies to individual
credentials when needed.
We specify policies in the verification request alongside the request_credentials parameter (previously explained),
using the vc_policies and vp_policies fields:
vc_policies and vp_policies each contain a list of policies; either one or both can be provided.
Identical structure: Both fields share the same structure.
Policy representation:
As a string if the policy does not require arguments.
As an object if the policy requires arguments.
Example Polices
[
"signature",
// policy without argument
"expired",
// policy without argument
"not-before",
// policy without argument
{
"policy": "webhook",
"args": "https://example.org/abc/xyz"
}
// policy with argument
]
authorizeBaseUrl - is used to modify the start of the OID4VC request URL. If you are using the
cross-device
flow, where you will display the URL as a QR code, you can leave the value as openid4vp://authorize or if you don't
know the wallet the user will be using to claim the credential. If you are using the same device flow, where you
already
know the user's wallet and want the user to be able to go directly to it, you can use the wallet URL path that is able
to
receive an OIDC request as a query parameter. Our wallet for example can receive OID4VC requests here
https://wallet.demo.walt.id/wallet-api/wallet/{wallet}/exchange/useOfferRequest.
responseMode - should be direct_post as the other options are not yet supported.
successRedirectUri (optional) - is used to redirect the user if verification is successful. You can use the $id
placeholder
to get access to the id of verification session in your application in order to retrieve the verification results.
E.g. /success?id=$id will be replaced with /success?id=1234567890
errorRedirectUri (optional) - is used to redirect the user if verification is unsuccessful. You can use the $id
placeholder
to get access to the id of verification session in your application in order to retrieve the verification results.
E.g. /error?id=$id will be replaced with /error?id=1234567890
statusCallbackUri (optional) - URL that should be called when the presentation request has been fulfilled by a
wallet. The request
sent will be a POST including the whole presentation
result. See Verification Status Policies Response
statusCallbackApiKey (optional) - If the endpoint you provide via statusCallbackUri is protected, you can use
the statusCallbackApiKey to authenticate.
The provided key will be appended as Authorization Header to the request.
stateId (optional) - overwrite the unique state value which gets created for each verification request with your
own.
openId4VPProfile (optional) - Define profile for VP (Verifiable Presentation) request. The default is W3C
OpenID4VP, which can optionally provided as DEFAULT.
Apart from that, you can choose from the following options:
HAIP: For the OID4VC HAIP profile.
EBSIV3: For EBSI V3 compliant VP. Learn more here.
ISO_18013_7_MDOC: For mdoc Openid4VP.
Body Parameters
vp_policies - Policies applied to the Verifiable Presentation. A list of policies can be
found here
vc_policies - Policies applied to all requested credentials. A list of policies can be
found here.
request_credentials - An array of objects detailing the credentials to be requested from the user. Each object
varies based on the type of credential being requested.
Expand To Learn More
Below are the possible credential types and their respective object structures:
format: Describes the format of the credential. For SD-JWT VC credentials, this would be
vc+sd-jwt.: Describes the format of the credential. For SD-JWT VC credentials, this would be vc+sd-jwt.
Per-credential policies: The OpenBadgeCredential object in request_credentials is extended with a policies
array so that additional checks apply only to this credential.
String vs. object policies:
"signature" does not require arguments and is therefore provided as a string.
"webhook" requires an argument and is therefore provided as an object with a policy and args field.
Policy reference: A list of different types of policies and their required arguments can be found
here.
Global policies remain in effect: The other requested credentials, "VerifiableId" and "ProofOfResidence",
do not define custom policies and are verified against the globally defined vp_policies and vc_policies.
authorizeBaseUrl - is used to modify the start of the OID4VC request URL. If you are using the
cross-device
flow, where you will display the URL as a QR code, you can leave the value as openid4vp://authorize or if you don't
know the wallet the user will be using to claim the credential. If you are using the same device flow, where you
already
know the user's wallet and want the user to be able to go directly to it, you can use the wallet URL path that is able
to
receive an OIDC request as a query parameter. Our wallet for example can receive OID4VC requests here
https://wallet.demo.walt.id/wallet-api/wallet/{wallet}/exchange/useOfferRequest.
responseMode - should be direct_post as the other options are not yet supported.
successRedirectUri (optional) - is used to redirect the user if verification is successful. You can use the $id
placeholder
to get access to the id of verification session in your application in order to retrieve the verification results.
E.g. /success?id=$id will be replaced with /success?id=1234567890
errorRedirectUri (optional) - is used to redirect the user if verification is unsuccessful. You can use the $id
placeholder
to get access to the id of verification session in your application in order to retrieve the verification results.
E.g. /error?id=$id will be replaced with /error?id=1234567890
statusCallbackUri (optional) - URL that should be called when the presentation request has been fulfilled by a
wallet. The request
sent will be a POST including the whole presentation
result. See Verification Status Policies Response
statusCallbackApiKey (optional) - If the endpoint you provide via statusCallbackUri is protected, you can use
the statusCallbackApiKey to authenticate.
The provided key will be appended as Authorization Header to the request.
stateId (optional) - overwrite the unique state value which gets created for each verification request with your
own.
openId4VPProfile (optional) - Define profile for VP (Verifiable Presentation) request. The default is W3C
OpenID4VP, which can optionally provided as DEFAULT.
Apart from that, you can choose from the following options:
HAIP: For the OID4VC HAIP profile.
EBSIV3: For EBSI V3 compliant VP. Learn more here.
ISO_18013_7_MDOC: For mdoc Openid4VP.
Body Parameters
vp_policies - Policies applied to the Verifiable Presentation. A list of policies can be
found here
vc_policies - Policies applied to all requested credentials. A list of policies can be
found here.
request_credentials - An array of objects detailing the credentials to be requested from the user. Each object
varies based on the type of credential being requested.
Expand To Learn More
Below are the possible credential types and their respective object structures:
format: Describes the format of the credential. For SD-JWT VC credentials, this would be
vc+sd-jwt.: Describes the format of the credential. For SD-JWT VC credentials, this would be vc+sd-jwt.
Add this input_descriptor as part of an object in the request_credentials array so it can be merged with the
auto-generated definition (see example below).
Important: Please also provide an id in the input_descriptor object.
On execution the verifier API will auto-generate the input descriptor for the VerifiableId credential that we specified via
the regular object and merge it with our custom input descriptor of the identity_credential to form the final presentation definition.
When using the input_descriptor make sure to also provide the presentation-definition policy in the
vp_policies array to ensure the constraints specified are checked during verification.
The presentation-definition policy also implements the
relational constraint feature.
These constraints let you define relations between issuer, holder and multiple credentials
within the input_descriptor.
Use this constraint when you want to ensure that the credential was self issued by the presenter. The verification will only succeed if the issuer DID matches the credential subject.
is_holder ensures the presenter actually holds the credential referenced by
the selected field(s). It checks that the credential was issued to the holder
who is submitting the presentation.
This constraint enforces that the fields referenced across several credentials
all relate to the same subject DID. Use it when multiple credentials must refer
to one entity.
Using the URL returned by the verification request, we can fulfill the request using the
hosted wallet by walt.id. Either show the URL as QR code and scan it with a camera or provide
the URL as is in the
text field below the camera once you click on "Scan to receive or present credentials" in the web wallet credentials
overview page in the top right corner.
After the user presents the credential(s), you can verify the status by performing the following call with the
state value obtained from the URL query params you shared with the user previously.
After a successful presentation session (verificationResult is true), you can retrieve a decoded and formatted
view of all credentials presented by the holder.
You can choose between two view modes:
simple: Recommended default view; provides a concise, human-friendly representation suitable for most use cases.
verbose: Provides additional technical detail useful for debugging, auditing, and in-depth inspection.
Endpoint:/openid4vc/session/{id}/presented-credentials | API Reference
viewMode - Echoed request value (or the default if it was not specified).
credentialsByFormat : A map where each key is a presentation format (jwt_vc_json, sd_jwt_vc, mso_mdoc)
and the value is an array of decoded presented credentials, formatted as JSON objects and whose properties vary
according to the value of viewMode:
For sd_jwt_vc in simple view mode:
vc - JSON object that provides the decoded IETF SD-JWT-VC credential and is composed of the following properties:
header - The JWT header section of the credential.
payload - The JWT payload section of the verifiable credential provided as a JSON
object with all disclosures (if provided) substituted.
keyBinding - JSON object that provides the decoded Key Binding JWT, assuming it was requested/provided in
the context of the presentation session and is composed of the following properties:
header - The JWT header section of the verifiable presentation provided as a JSON object.
payload - The JWT payload section of the verifiable presentation provided as a JSON object.
For sd_jwt_vc in verbose view mode:
raw - The compact serialized IETF SD-JWT-VC.
vc - JSON object that provides verbosely decoded IETF SD-JWT-VC and is composed of the following
properties:
header - The JWT header section of the IETF SD-JWT-VC provided as a JSON object.
fullPayload - The JWT payload section of the IETF SD-JWT-VC provided as a JSON
object with all disclosures (if provided) substituted.
undisclosedPayload - The JWT payload section of the IETF SD-JWT-VC provided as a JSON
object without any disclosures substituted (if provided).
disclosures - A map between selective disclosure (hashed) values and a JSON object that provides
their decoded representation as provided by the wallet. This property is only present if disclosable
claims were requested/provided in the context of the presentation session.
keyBinding - JSON object that provides the decoded Key Binding JWT, assuming it was requested/provided in
the context of the presentation session and is composed of the following properties:
header - The JWT header section of the verifiable presentation provided as a JSON object.
payload - The JWT payload section of the verifiable presentation provided as a JSON object.
In the following we provide an example that involves the presentation of an IETF SD-JWT-VC Identity Credential
with two disclosable claims, namely, the family_name and birthdate properties.