Wallet Integration
This guide explains how to configure the Wallet Service to obtain and use client attestations when requesting credentials from issuers that require attestation-based client authentication.
Overview
The wallet integration involves two steps:
- Obtain an attestation – The wallet requests an attestation JWT from a Client Attestation Service
- Use the attestation – The wallet includes the attestation in credential requests to issuers
Prerequisites
Before configuring wallet attestation:
- Wallet Service – An existing Wallet Service in your tenant
- Client Attestation Service – A configured Client Attestation Service in your tenant
- Wallet Key – A key in the wallet's KMS that will be used as the instance key
Link the Client Attester to the Wallet
First, add the Client Attestation Service as a dependency of the Wallet Service.
Endpoint: /v1/{target}/wallet-service-api/dependencies/add | API Reference
Example Request
curl -X 'POST' \
'https://{orgID}.enterprise-sandbox.waltid.dev/v1/{target}/wallet-service-api/dependencies/add' \
-H 'accept: */*' \
-H 'Authorization: Bearer {yourToken}' \
-H 'Content-Type: text/plain' \
-d 'waltid.tenant1.client-attester1'
Path Parameters
orgID– Your organization's Base URLtarget– The wallet service target ({organizationID}.{tenantID}.{walletServiceID}), e.g.waltid.tenant1.wallet1
Body
The resource identifier of the Client Attestation Service to link, e.g. waltid.tenant1.client-attester1
Response Codes
201– Dependency added successfully
Obtain a Client Attestation
The wallet must obtain an attestation JWT before it can request credentials from issuers that require attestation. The attestation is stored in the wallet's resource tree and can be reused until it expires.
Endpoint: /v1/{target}/wallet-service-api/client-attestation/obtain
Example Request
curl -X 'POST' \
'https://{orgID}.enterprise-sandbox.waltid.dev/v1/{target}/wallet-service-api/client-attestation/obtain' \
-H 'accept: application/json' \
-H 'Authorization: Bearer {yourToken}' \
-H 'Content-Type: application/json' \
-d '{
"clientAttesterServiceRef": "waltid.tenant1.client-attester1",
"instanceKeyReference": "waltid.tenant1.kms1.wallet_key"
}'
Body
{
"clientAttesterServiceRef": "waltid.tenant1.client-attester1",
"instanceKeyReference": "waltid.tenant1.kms1.wallet_key"
}
Path Parameters
orgID– Your organization's Base URLtarget– The wallet service target ({organizationID}.{tenantID}.{walletServiceID}), e.g.waltid.tenant1.wallet1
Body Parameters
clientAttesterServiceRef: resourceIdentifier – Reference to the Client Attestation Service that will issue the attestationinstanceKeyReference: resourceIdentifier – Reference to the wallet's instance key in the KMS. The public key will be embedded in the attestation'scnf.jwkclaim.
Response
{
"clientAttestationJwt": "eyJhbGciOiJFUzI1NiIsInR5cCI6Im9hdXRoLWNsaWVudC1hdHRlc3RhdGlvbitqd3QifQ...",
"expiresAt": 1715270400
}
Response Fields
clientAttestationJwt: String – The signed attestation JWTexpiresAt: Long – Unix timestamp when the attestation expires
Response Codes
200– Attestation obtained successfully400– Invalid request404– Client Attester Service or key not found
Check Current Attestation
You can retrieve the wallet's current stored attestation to check its status or expiration.
Endpoint: /v1/{target}/wallet-service-api/client-attestation/current
Example Request
curl -X 'GET' \
'https://{orgID}.enterprise-sandbox.waltid.dev/v1/{target}/wallet-service-api/client-attestation/current' \
-H 'accept: application/json' \
-H 'Authorization: Bearer {yourToken}'
Path Parameters
orgID– Your organization's Base URLtarget– The wallet service target ({organizationID}.{tenantID}.{walletServiceID}), e.g.waltid.tenant1.wallet1
Response
{
"clientAttestationJwt": "eyJhbGciOiJFUzI1NiIsInR5cCI6Im9hdXRoLWNsaWVudC1hdHRlc3RhdGlvbitqd3QifQ...",
"expiresAt": 1715270400,
"instanceKeyId": "waltid.tenant1.kms1.wallet_key"
}
Response Codes
200– Current attestation returned404– No attestation found for this wallet
Use Attestation When Receiving Credentials
When requesting credentials from an issuer that requires attestation, set useClientAttestation: true in the receive request. The wallet will automatically:
- Load the stored attestation
- Build a fresh PoP JWT signed with the instance key
- Include both in the token request headers
Endpoint: /v2/{target}/wallet-service-api/credentials/receive/pre-authorized
Example Request
curl -X 'POST' \
'https://{orgID}.enterprise-sandbox.waltid.dev/v2/{target}/wallet-service-api/credentials/receive/pre-authorized' \
-H 'accept: application/json' \
-H 'Authorization: Bearer {yourToken}' \
-H 'Content-Type: application/json' \
-d '{
"offerUrl": "openid-credential-offer://issuer.example.org/issue/?credential_offer_uri=...",
"keyReference": "waltid.tenant1.kms1.wallet_key",
"useClientAttestation": true
}'
Body
{
"offerUrl": "openid-credential-offer://issuer.example.org/issue/?credential_offer_uri=...",
"keyReference": "waltid.tenant1.kms1.wallet_key",
"useClientAttestation": true
}
Body Parameters
offerUrl: String – The credential offer URL from the issuerkeyReference: resourceIdentifier – Reference to the wallet's key (must match the instance key used when obtaining the attestation)useClientAttestation: Boolean – Whentrue, the wallet includes attestation headers in the token request
Attestation Lifecycle
Expiration
Attestations have a configurable validity period (default: 24 hours). When an attestation expires:
- The wallet will receive an error when trying to use it
- The issuer may return a
use_fresh_attestationerror code - The wallet must obtain a new attestation before retrying
Refresh Strategy
For production deployments, consider implementing an attestation refresh strategy:
- Proactive refresh – Obtain a new attestation before the current one expires
- Reactive refresh – Obtain a new attestation when the issuer returns
use_fresh_attestation
Error Handling
| Error | Description | Resolution |
|---|---|---|
use_fresh_attestation | Attestation has expired | Obtain a new attestation and retry |
invalid_client | Attestation signature verification failed | Check that the issuer trusts the attester's key |
invalid_client | PoP signature verification failed | Ensure the wallet is using the correct instance key |
invalid_client | PoP aud mismatch | Verify the issuer's RFC 8414 issuer identifier URL |
Next Steps
- Configure Issuer Integration – Set up issuers to require attestation verification
