WUA explained: how a wallet proves itself to an issuer
A Wallet Unit Attestation, WUA, is what an EUDI Wallet shows a PID Provider or Attestation Provider during issuance to prove it is genuine. It is not one document but two, both signed by the Wallet Provider: a Wallet Instance Attestation (WIA) about the wallet app, and a Key Attestation (KA) about the secure storage of the keys a credential will be bound to.
The problem a WUA solves
An issuer about to hand a PID or a company registration credential to a wallet has no built-in way to tell a certified EUDI Wallet from a modified app or a script replaying an authorization flow. Nor can it see whether the key the credential will be bound to lives in certified secure hardware, or in ordinary storage it could be copied from.
The WUA closes both gaps. The Wallet Provider vouches for the app through the WIA and for the key storage through the Key Attestation. The issuer checks both before issuing, and keeps checking their revocation status afterwards, so it can revoke what it issued if the wallet or its key storage is later found to be compromised.
A WUA is used only during issuance. The ARF forbids a Wallet Unit from presenting a WIA or Key Attestation to a Relying Party, which keeps wallet details out of every presentation.
The actors and who trusts whom
Five roles are involved, and only four of them ever handle a WUA. The WSCD (Wallet Secure Cryptographic Device) or a keystore generates and guards the keys, the Wallet Provider vouches for the app and the keys, and the issuer relies on that instead of assessing the wallet itself.
Wallet Provider
Signs WIAs and Key Attestations after checking the app and the key storage, and runs the Status Lists for both
Wallet Unit
Sends a WIA and a Key Attestation to the issuer during issuance, and uses each for one issuance only
WSCD or keystore
Generates and holds the private keys a Key Attestation describes
PID Provider or Attestation Provider
Verifies the WIA and Key Attestation, binds the credential to an attested key, and keeps checking both for revocation
Relying Party
Never receives a WUA. It checks the credential, its device binding and its revocation status instead
Issuers trust a WUA because the Wallet Provider’s signing certificate, sent in the x5c header, chains to a trust anchor on the Trusted List for Wallet Providers. The Wallet Solution itself is certified by a conformity assessment body, and the WIA carries that certification information.
Two attestations under one name
TS3, the EUDI technical specification for WUAs, splits the attestation in two because the app and the key storage are different things, checked at different endpoints and revoked for different reasons.
Wallet Instance Attestation (WIA)
- Attests
- The integrity of the Wallet Instance, meaning the app
- Sent to
- The Authorization Server, in the Pushed Authorization Request and the Token Request
- Lifetime
- Less than 24 hours
- Revocation
- client_status: the revocation state of this Wallet Instance
- Needed for
- Every issuance, device-bound or not
Key Attestation (KA)
- Attests
- That one or more keys were generated in and are held by a named WSCD or keystore, and how well that storage resists attack
- Sent to
- The Credential Issuer, inside the proofs of the Credential Request
- Lifetime
- Chosen by the Wallet Provider, and may be longer than a WIA
- Revocation
- key_storage_status: the revocation state of the WSCD or keystore
- Needed for
- Device-bound credentials only, including every PID
Both are JWTs signed by the Wallet Provider with ES256, ES384 or ES512. A Key Attestation is used for one issuance only, and a WIA is never reused towards a different issuer, so issuers cannot link requests from the same wallet.
How a Wallet Unit obtains its WIAs and Key Attestations
TS3 leaves this step to each Wallet Provider, since it happens inside one wallet product. The ARF only requires the Wallet Provider to verify the app’s integrity before signing a WIA, and to verify that the attested private keys really sit in the named WSCD or keystore before signing a Key Attestation. A typical flow, using platform attestations such as Google Play Integrity or Apple DeviceCheck as evidence, looks like this.
1. Wallet Unit
Asks the WSCD or keystore to generate key pairs
2. WSCD or keystore
Returns the public keys, with platform evidence of where they were generated
3. Wallet Provider
Checks the app’s integrity and the key evidence, then signs WIAs and Key Attestations
4. Wallet Unit
Keeps a supply of fresh WIAs and Key Attestations, and uses a new one for each issuance
What a WIA and a Key Attestation contain
Neither carries an iss claim: the issuer identifies the Wallet Provider from the signing certificate in the x5c header. The examples below are decoded, with header and payload separated by a dot.
Wallet Instance Attestation
{
"typ": "oauth-client-attestation+jwt",
"alg": "ES256",
"x5c": ["MIIC..."]
}.{
"sub": "https://wallet.example.eu",
"wallet_name": "ExampleWallet-mobile",
"wallet_version": "2.3.0",
"wallet_link": "https://wallet.example.eu/about",
"wallet_solution_certification_information": "https://wallet.example.eu/certification/2-3-0",
"exp": 1789329600,
"client_status": {
"status": {
"status_list": { "idx": 48213, "uri": "https://wallet.example.eu/status/wia/17" }
},
"exp": 1791936000
},
"cnf": {
"jwk": { "kty": "EC", "crv": "P-256", "x": "...", "y": "..." }
}
}| Field | What it tells the issuer |
|---|---|
| typ / x5c | That this is a client attestation, and the Wallet Provider’s certificate chain to check against the Trusted List |
| sub | The wallet type, the same for every installation, so it cannot be used to track a user |
| wallet_name / wallet_version | The Wallet Solution as listed on the Trusted List, and its version |
| wallet_solution_certification_information | Who certified the Wallet Solution; the exact content is still to be defined |
| exp | Technical expiry, less than 24 hours after the integrity check |
| client_status | A Status List entry for this Wallet Instance, and the date until which the Wallet Provider keeps it up to date |
| cnf | The key that signs the proof of possession sent along with the WIA |
Key Attestation
{
"typ": "key-attestation+jwt",
"alg": "ES256",
"x5c": ["MIIC..."]
}.{
"iat": 1789257600,
"exp": 1791936000,
"certification": "https://wallet.example.eu/certification/wscd/secure-element",
"key_storage": ["iso_18045_high"],
"user_authentication": ["iso_18045_high"],
"attested_keys": [
{ "kty": "EC", "crv": "P-256", "x": "...", "y": "..." },
{ "kty": "EC", "crv": "P-256", "x": "...", "y": "..." }
],
"key_storage_status": {
"status": {
"status_list": { "idx": 3, "uri": "https://wallet.example.eu/status/ka/1" }
},
"exp": 1794614400
}
}| Field | What it tells the issuer |
|---|---|
| typ / x5c | That this is a key attestation, and the Wallet Provider’s certificate chain to check against the Trusted List |
| iat / exp | When it was issued and when it technically expires |
| attested_keys | Public keys whose private keys the WSCD or keystore generated and holds; several keys allow batch issuance |
| key_storage / user_authentication | How well the storage, and the user authentication that unlocks the keys, resist attack; a WSCD is always iso_18045_high for both |
| certification | The certification of the WSCD or keystore, from which the issuer can tell whether it is a WSCD |
| key_storage_status | A Status List entry for the WSCD or keystore, and the date until which the Wallet Provider keeps it up to date |
| nonce | The issuer’s c_nonce, present only when the Key Attestation is sent as an attestation proof |
Where a WUA travels during OpenID4VCI issuance
The two attestations go to different places. The WIA authenticates the wallet as an OAuth client at the Authorization Server. The Key Attestation goes to the Credential Issuer with the request for the credential itself.
Authorization Server receives the WIA
- The WIA signature chains to the Trusted List for Wallet Providers
- The WIA has not expired and the Wallet Instance is not revoked
- The proof of possession is signed with the key in the WIA’s cnf claim
Credential Issuer receives the Key Attestation
- The Key Attestation signature chains to the Trusted List for Wallet Providers
- The issuer’s fresh c_nonce is in the jwt proof or in the Key Attestation itself
- The WSCD or keystore is not revoked, and the credential is bound to one of the attested_keys
Pushed Authorization Request with the WIA
POST /par HTTP/1.1 Host: issuer.example.eu Content-Type: application/x-www-form-urlencoded OAuth-Client-Attestation: <WIA JWT> OAuth-Client-Attestation-PoP: <PoP JWT signed with the WIA cnf key> response_type=code &client_id=https%3A%2F%2Fwallet.example.eu &scope=company_registration &code_challenge=<S256 challenge> &code_challenge_method=S256 &redirect_uri=<wallet redirect URI>
The client_id matches the sub of the WIA. The Token Request carries the same two headers. Because the Credential Issuer never sees the WIA, the Authorization Server has to pass its client_status on, for example inside the access token.
Credential Request with the Key Attestation
POST /credential HTTP/1.1
Host: issuer.example.eu
Authorization: DPoP <access_token>
DPoP: <DPoP proof JWT>
Content-Type: application/json
{
"credential_configuration_id": "company_registration",
"proofs": {
"jwt": ["<proof JWT: Key Attestation in its key_attestation header, signed with attested_keys[0]>"]
}
}With the attestation proof type, the request carries "proofs": { "attestation": ["<Key Attestation JWT>"] } instead. There is no proof of possession then: the Wallet Unit passes the issuer’s c_nonce to the Wallet Provider, which puts it in a freshly signed Key Attestation.
The WUA lifecycle
A WUA is short-lived and single-use on purpose, but the revocation information behind it outlives the token itself. The first three stages are routine; the fourth only happens when something goes wrong.
1. Issuance
The Wallet Provider signs WIAs and Key Attestations after its integrity and key storage checks
2. Single use
Each one serves a single issuance, so the Wallet Unit keeps obtaining fresh ones
3. Revocation chaining
A PID Provider re-checks the WIA and Key Attestation status at least every 24 hours, and revokes the PID if either is revoked
4. Revocation
The Wallet Provider revokes a Wallet Instance, for example after loss or theft, or a WSCD or keystore with a security vulnerability
Outside the EUDI Wallet ecosystem, some Wallet Providers issue wallet attestations with a very short lifespan and no status reference at all, relying on expiry instead of revocation; OpenID4VCI makes the status claim optional. TS3 does not allow that for EUDI Wallets. The WIA already lives less than 24 hours, yet both the WIA and the Key Attestation must carry a status reference that the Wallet Provider maintains for at least 31 days, because PID Providers use it to revoke PIDs long after issuance.
WUA, WIA and KA: which term means what
The terminology changed while the specifications matured. TS3 called the WIA a Wallet App Attestation until version 1.1, and used WUA for what is now the Key Attestation until version 1.5. Older articles and ARF drafts therefore use the terms differently.
| Term | What it covers | Who receives it |
|---|---|---|
| WUA | Umbrella term for the two attestations below | PID Providers and Attestation Providers, during issuance only |
| WIA | The Wallet Instance, meaning the app | The Authorization Server, in the Pushed Authorization Request and Token Request |
| KA | A WSCD or keystore and the keys it holds | The Credential Issuer, in the proofs of the Credential Request |
Related terms
Frequently asked questions
Is a WUA the same thing as a Wallet Instance Attestation?
No. Since version 1.5 of TS3, WUA is the umbrella term for two attestations: the Wallet Instance Attestation (WIA), which covers the app, and the Key Attestation (KA), which covers the WSCD or keystore holding the keys. Older documents use WUA for what is now called the Key Attestation, which is why the terms are often confused.
Does a verifier ever see the WUA?
No. ARF requirements WUA_07 and WUA_24 allow a Wallet Unit to present a WIA or Key Attestation only to a PID Provider or Attestation Provider during issuance, never to a Relying Party. A verifier checks the credential instead: its signature, its device binding and its revocation status. If the wallet behind a PID is revoked, the PID Provider revokes the PID within its 24-hour check cycle, and the verifier sees that through the PID’s own status.
How long is a WUA valid?
A WIA expires less than 24 hours after the Wallet Provider checked the app’s integrity. A Key Attestation can be valid for longer, at the Wallet Provider’s discretion. Separately, each carries a status maintenance date, client_status.exp or key_storage_status.exp, until which the Wallet Provider keeps the revocation status up to date. The Wallet Unit must always be able to present one whose date is at least 31 days away, and a PID must expire before that date.
What happens if a wallet unit is compromised before its WUA expires?
The Wallet Provider revokes the Wallet Instance on its WIA Status List, or, for a vulnerability in a type of WSCD or keystore, the Status List entry for that storage. A PID Provider checks the WIA and Key Attestation status behind every PID it issued at least once every 24 hours and revokes the PID when either is revoked. Attestation Providers may do the same. Expiry of the WUA itself is not what removes the wallet; the revocation of the credentials issued to it is.
Can one Key Attestation cover more than one key?
Yes. attested_keys can list several public keys from the same WSCD or keystore, which is how batch issuance works: the issuer binds each credential in the batch to a different key, and one Wallet Provider signature covers all of them. When the Key Attestation travels in a jwt proof, the Wallet Unit signs that proof with the first key in the list only.
Sources
This page is informational and does not constitute legal advice. For authoritative guidance consult the European Commission and the OpenID Foundation directly.