Wallet Integration
This guide explains how to configure a Wallet2 Service to obtain and use client attestations when requesting credentials from issuers that require attestation-based client authentication.
The same obtain/current attestation endpoints exist on the legacy Wallet Service (/v1) when wallet-draft-routes is enabled. Prefer Wallet2 (type: wallet2, /v2) for new integrations.
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 or Wallet2 Service – An existing Wallet2 Service or 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 Wallet2 Service.
Endpoint: /{version}/{target}/wallet-service-api/dependencies/add | API Reference
Example Request
curl -X 'POST' \
'https://{orgID}.enterprise-sandbox.waltid.dev/{version}/{target}/wallet-service-api/dependencies/add' \
-H 'accept: */*' \
-H 'Authorization: Bearer {yourToken}' \
-H 'Content-Type: application/json' \
-d '{
"dependency": "waltid.tenant1.client-attester1"
}'
Path Parameters
orgID– Your organization's Base URLtarget– The wallet service target ({organizationID}.{tenantID}.{walletServiceID}), e.g.waltid.tenant1.wallet1version: version - The version of the Wallet Service API to use. In our casev1orv2
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: /{version}/{target}/wallet-service-api/client-attestation/obtain
Example Request
curl -X 'POST' \
'https://{orgID}.enterprise-sandbox.waltid.dev/{version}/{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.wallet1version: version - The version of the Wallet Service API to use. In our casev1orv2
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,
"storedAt": "waltid.tenant1.wallet1.client-attestation"
}
Response Fields
clientAttestationJwt: String – The signed attestation JWTexpiresAt: Long – Unix timestamp when the attestation expiresstoredAt: String – Resource path where the attestation was stored
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: /{version}/{target}/wallet-service-api/client-attestation/current
Example Request
curl -X 'GET' \
'https://{orgID}.enterprise-sandbox.waltid.dev/{version}/{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.wallet1version: version - The version of the Wallet Service API to use. In our casev1orv2
Response
{
"_id": "waltid.tenant1.wallet1.client-attestation",
"createdAt": "2026-05-21T15:00:00Z",
"updatedAt": "2026-05-21T15:00:00Z",
"clientAttestationJwt": "eyJhbGciOiJFUzI1NiIsInR5cCI6Im9hdXRoLWNsaWVudC1hdHRlc3RhdGlvbitqd3QifQ...",
"expiresAt": 1715270400,
"attesterServiceRef": "waltid.tenant1.client-attester1",
"parent": "waltid.tenant1.wallet1"
}
Response Fields
_id: String – Resource path of the stored attestation ({walletTarget}.client-attestation)createdAt/updatedAt: String – ISO-8601 timestamps for when the attestation was first obtained / last refreshedclientAttestationJwt: String – The signed attestation JWTexpiresAt: Long – Unix timestamp when the attestation expiresattesterServiceRef: String – Resource path of the Client Attestation Service that issued this attestationparent: String – The wallet's own resource path
Response Codes
200– Current attestation returned404– No attestation found for this wallet
Discover What the Issuer Expects
Before driving a receive flow, resolve the issuer’s OAuth 2.0 Authorization Server metadata (RFC 8414) for the OID4VCI authorization server referenced by the offer. In particular:
- If
token_endpoint_auth_methods_supportedincludesattest_jwt_client_auth, the issuer is configured for attestation-based client authentication and the wallet must send theOAuth-Client-AttestationandOAuth-Client-Attestation-PoPheaders on the token request (for example by settinguseClientAttestation: trueon wallet receive APIs, after obtaining an attestation). - If
pre_authorized_grant_anonymous_access_supportedistrue, the issuer allows pre-authorized code token requests withoutclient_idwhen no attestation is used. If it isfalseand attestation is not advertised, your client may need to sendclient_idor use another supported method per the issuer’s configuration.
These flags follow the issuer’s clientAuthenticationConfig in the enterprise API (see Issuer integration).
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
