---
title: "Wallet Integration"
description: "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."
stack: "Enterprise Stack (commercial) — version 0.21.0"
stack_version: "0.21.0"
stack_comparison: https://docs.walt.id/community-vs-enterprise.md
canonical_url: https://docs.walt.id/enterprise-stack/services/client-attestation-service/wallet-integration
generated: 2026-07-20
---
# 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:

1. **Obtain an attestation** – The wallet requests an attestation JWT from a Client Attestation Service
2. **Use the attestation** – The wallet includes the attestation in credential requests to issuers

## Prerequisites

Before configuring wallet attestation:

1. **Wallet Service** – An existing [Wallet Service](https://docs.walt.id/enterprise-stack/services/wallet-service/setup.md) in your tenant
2. **Client Attestation Service** – A configured [Client Attestation Service](https://docs.walt.id/enterprise-stack/services/client-attestation-service/setup.md) in your tenant
3. **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.

**Option: CURL**

Endpoint: `/v1/{target}/wallet-service-api/dependencies/add` | [API Reference](https://enterprise.sandbox.walt.id/swagger/index.html#/Service%20%7C%20Wallet%20Service/post_v1__target__wallet_service_api_dependencies_add)

**Example Request**

```bash
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 URL
- `target` – 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.

**Option: CURL**

Endpoint: `/v1/{target}/wallet-service-api/client-attestation/obtain`

**Example Request**

```bash
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**

```json
{
  "clientAttesterServiceRef": "waltid.tenant1.client-attester1",
  "instanceKeyReference": "waltid.tenant1.kms1.wallet_key"
}
```

**Path Parameters**

- `orgID` – Your organization's Base URL
- `target` – 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 attestation
- `instanceKeyReference`: _resourceIdentifier_ – Reference to the wallet's instance key in the KMS. The public key will be embedded in the attestation's `cnf.jwk` claim.

---

**Response**

```json
{
  "clientAttestationJwt": "eyJhbGciOiJFUzI1NiIsInR5cCI6Im9hdXRoLWNsaWVudC1hdHRlc3RhdGlvbitqd3QifQ...",
  "expiresAt": 1715270400
}
```

**Response Fields**

- `clientAttestationJwt`: _String_ – The signed attestation JWT
- `expiresAt`: _Long_ – Unix timestamp when the attestation expires

---

**Response Codes**

- `200` – Attestation obtained successfully
- `400` – Invalid request
- `404` – 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.

**Option: CURL**

Endpoint: `/v1/{target}/wallet-service-api/client-attestation/current`

**Example Request**

```bash
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 URL
- `target` – The wallet service target (`{organizationID}.{tenantID}.{walletServiceID}`), e.g. `waltid.tenant1.wallet1`

---

**Response**

```json
{
  "clientAttestationJwt": "eyJhbGciOiJFUzI1NiIsInR5cCI6Im9hdXRoLWNsaWVudC1hdHRlc3RhdGlvbitqd3QifQ...",
  "expiresAt": 1715270400,
  "instanceKeyId": "waltid.tenant1.kms1.wallet_key"
}
```

---

**Response Codes**

- `200` – Current attestation returned
- `404` – 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_supported` includes `attest_jwt_client_auth`, the issuer is configured for attestation-based client authentication and the wallet must send the `OAuth-Client-Attestation` and `OAuth-Client-Attestation-PoP` headers on the token request (for example by setting `useClientAttestation: true` on wallet receive APIs, after obtaining an attestation).
- If `pre_authorized_grant_anonymous_access_supported` is `true`, the issuer allows **pre-authorized code** token requests **without** `client_id` when no attestation is used. If it is `false` and attestation is not advertised, your client may need to send `client_id` or use another supported method per the issuer’s configuration.

These flags follow the issuer’s `clientAuthenticationConfig` in the enterprise API (see [Issuer integration](https://docs.walt.id/enterprise-stack/services/client-attestation-service/issuer-integration.md)).

## 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:

1. Load the stored attestation
2. Build a fresh PoP JWT signed with the instance key
3. Include both in the token request headers

**Option: CURL**

Endpoint: `/v2/{target}/wallet-service-api/credentials/receive/pre-authorized`

**Example Request**

```bash
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**

```json
{
  "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 issuer
- `keyReference`: _resourceIdentifier_ – Reference to the wallet's key (must match the instance key used when obtaining the attestation)
- `useClientAttestation`: _Boolean_ – When `true`, 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:

1. The wallet will receive an error when trying to use it
2. The issuer may return a `use_fresh_attestation` error code
3. 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](https://docs.walt.id/enterprise-stack/services/client-attestation-service/issuer-integration.md) – Set up issuers to require attestation verification
