EUDI Wallet Flows
This page shows how the wallet uses the keystore to obtain a credential (OpenID4VCI) and to present it (OpenID4VP), and lists every key, attestation, proof and token involved. Terms are explained in the Glossary.
These flows are the target design; the REST endpoints they use are not implemented yet.
Every keystore call in these flows is a user request: the wallet signs it with the device keys after a vault unlock and encrypts it, and the Wallet Integration Server forwards it unchanged (see PowerAuth Integration). The Wallet Integration Server cannot read the bodies. The calls to the authorization server and the issuer involve neither it nor the keystore.
An issuance makes three keystore calls: WIA key, WIA, and credential keys. The user enters the PIN or uses biometry once per flow; the SDK then unlocks the vault for each of the three calls. The WIA key has its own call because a refresh reuses it.
Curve. The EUDI user keys, the KA and WIA provider keys and diw-gateway’s EUDI keys are EC P-256, as required today by the OpenID4VC High Assurance Interoperability Profile (HAIP) and the EUDI technical specification TS3. EC P-384 will follow once the EUDI ecosystem supports it. The user-signing keys are EC P-384, plus ML-DSA for a hybrid activation.
Timing. The Wallet Integration Server registers the activation as a unit during the activation, before the commit, and revokes the unit when the activation is removed. KAs and WIAs are not created at activation but just in time, because a key attestation must contain the issuer’s c_nonce.
Issuance of a Credential (OpenID4VCI)

- WIA key (
wallet-instance-keys). The keystore creates aWALLET_INSTANCEkey and returns its public key and its wrapped key. The public key becomes the WIA’scnf. The ARF calls this key the client instance key. - WIA (
wallet-instance-attestations). The wallet sends the WIA key’s public key, its wrapped key, and the unsigned proof-of-possession (PoP) JWTs for the pushed authorization request (PAR) and the token request. The keystore checks the PoPs, signs them with the WIA key and verifies the signatures. It returns them with a WIA signed bysign-eudi-ecdsa-wia, valid for 10 minutes. - Credential keys (
credential-keys). The wallet sends the number of keys (up to 16) and the issuer’sc_nonce. The keystore creates theCREDENTIALkeys and returns them with a key attestation (KA) signed bysign-eudi-ecdsa-ka. For issuers that require the proof typejwt, the wallet also asks for the proof JWT, which the keystore signs.
Refresh. With a refresh token, the wallet asks the keystore for a new WIA and PoP for the same WIA key. For a re-issuance, it also creates a new key batch with a new KA. The issuer accepts the new attested keys for the same grant.
Presentation of a Credential (OpenID4VP)

The wallet presents an SD-JWT VC (selective-disclosure JWT verifiable credential) with a key-binding JWT (KB-JWT). To sign the KB-JWT, it sends the keystore only the SHA-256 of the KB-JWT’s signing input and the credential’s wrapped key (key-binding-signatures). The same call signs the device authentication of an ISO/IEC 18013-5 mdoc.
The keystore accepts only a CREDENTIAL key. It never sees the credential, the disclosures or the verifier. The Wallet Integration Server sees only the encrypted envelope, and the verifier is not involved in the keystore call.
Keys, Attestations, Proofs and Tokens
Wrap and unwrap use the wrap key wrap-user-ecdsa-<n> (AES key wrap); seal and open use the bind key bind-user-ecdsa-<n> (AES-GCM). Every created or unwrapped private key is destroyed right after use.
Shared Keys
| Item | Type | Count | Lifetime | Stored | What the HSM does |
|---|---|---|---|---|---|
wrap-user-ecdsa-<n>, bind-user-ecdsa-<n> |
key | 1 pair per generation <n> |
until no wrapped key of <n> is in use |
HSM, user token |
create: wrap, seal; sign: open, unwrap |
| Provider CA certificate | certificate | 1 | validity of the certificate | HSM, eudi token |
none; see note below |
The provider CA issues the WIA and KA signing certificates and is sent in x5c after the leaf. The self-signed root above it is the trust anchor and is never in x5c.
Wallet Instance Attestation (WIA)
| Item | Type | Count | Lifetime | Stored | What the HSM does |
|---|---|---|---|---|---|
sign-eudi-ecdsa-wia and its certificate |
key | 1 | validity of its certificate | HSM, eudi token |
signs each WIA |
WIA key (cnf, purpose WALLET_INSTANCE) |
key | 1 per grant | until the refresh token expires | app storage, wrapped | create: generate, wrap, seal; each PoP: open, unwrap, sign |
| WIA | attestation | 1 per issuance or refresh | 10 minutes | – | signed by sign-eudi-ecdsa-wia |
| WIA PoP | proof | 1 per PAR or token request | one request | – | signed by the WIA key |
Key Attestation (KA)
| Item | Type | Count | Lifetime | Stored | What the HSM does |
|---|---|---|---|---|---|
sign-eudi-ecdsa-ka and its certificate |
key | 1 | validity of its certificate | HSM, eudi token |
signs each KA |
Credential key (purpose CREDENTIAL) |
key | 1 per credential, 1–16 per KA | as long as its credential | app storage, wrapped | create: generate, wrap, seal; each presentation: open, unwrap, sign |
| KA | attestation | 1 per key batch | 10 minutes | – | signed by sign-eudi-ecdsa-ka |
Proof JWT (proof type jwt) |
proof | 1 per credential request | one request (c_nonce) |
– | signed by credential key 0 before it is wrapped |
| KB-JWT or mdoc device authentication | proof | 1 per presentation | one presentation (nonce) |
– | hash signed by the credential key |
A wrapped key in app storage is useless without the device keys.
Wallet Only
These items never reach the Secure Keystore.
| Item | Type | Count | Lifetime | Stored |
|---|---|---|---|---|
| PowerAuth activation and its device keys | activation | 1 per device | until removed | iOS Keychain / Android Keystore (PowerAuth SDK); device keys encrypted in the vault |
| Credential (SD-JWT VC or mdoc) | credential | 1 per credential key | set by the issuer | encrypted app storage (personal data) |
| Refresh token | token | 1 per grant | set by the issuer | iOS Keychain / Android Keystore; bound to the WIA key |
| Access token | token | 1 per token request | short, set by the issuer | memory |
| DPoP key | key | 1 or more per grant | as long as its access tokens | iOS Keychain / Android Keystore (hardware-backed where available) |
The device keys sign every keystore request.
Notes
- The WIA lifetime is configurable and always below 24 hours.
- A credential key could sign every presentation of its credential, but each credential of a batch should be presented only once, for unlinkability.
- A refresh needs a new WIA and PoP. A re-issuance also needs a new KA and new keys. Rotation of the refresh token follows the issuer’s policy.
- Keys in the HSM for the EUDI flows: the two provider keys (one more of each during rotation) and the wrap and bind keys of each accepted generation, for
user-ecdsaand, on an HSM with ML-DSA,user-mldsa.