Proof of Possession
How wallets prove control of a private key during credential issuance, enabling key binding for holder authentication during presentation.
What is Proof of Possession?
Proof of Possession (PoP) demonstrates that the wallet controls a private key. The issuer binds the corresponding public key to the credential, enabling holder authentication during presentation.
Key Generation
Wallet generates a key pair (typically in secure hardware). Private key never leaves the device.
c_nonce
Server-provided nonce ensures the proof is fresh and wasn't created for a different request.
Signed Proof
Wallet signs a JWT or CWT containing the nonce using its private key.
Key Binding
Issuer embeds the public key in the credential. Holder must use this key during presentation.
JWT Proof Format
The most common proof type. A JWT signed by the wallet's private key, containing the issuer's nonce.
Header
{
"typ": "openid4vci-proof+jwt",
"alg": "ES256",
"kid": "did:key:z6MkiK...#z6MkiK..."
}- typ
- Must be "openid4vci-proof+jwt"
- alg
- Signing algorithm (ES256, EdDSA, etc.)
- kid
- Key identifier (DID URL or JWK thumbprint)
Payload
{
"iss": "did:key:z6MkiK...",
"aud": "https://issuer.example.com",
"iat": 1704067200,
"nonce": "tZignsnFbp"
}JWT Proof Claims
| Claim | Name | Required | Purpose |
|---|---|---|---|
| iss | Issuer | Required | DID or client_id of the wallet. Identifies the key controller. |
| aud | Audience | Required | Credential issuer identifier (from metadata). Prevents token reuse. |
| iat | Issued At | Required | Unix timestamp when proof was created. Must be recent. |
| nonce | Nonce | Required | The c_nonce from issuer. Proves freshness. |
CWT Proof Format
For ISO mDOC credentials, CBOR Web Token (CWT) proofs may be used. Same claims as JWT but in CBOR encoding with COSE signature.
COSE_Sign1 = [
/ protected / << {
/ typ / 16: "openid4vci-proof+cwt",
/ alg / 1: -7 / ES256 /
} >>,
/ unprotected / {
/ kid / 4: h'...'
},
/ payload / << {
/ iss / 1: "did:key:z6MkiK...",
/ aud / 3: "https://issuer.example.com",
/ iat / 6: 1704067200,
/ nonce / 10: "tZignsnFbp"
} >>,
/ signature / h'...'
]When to Use CWT
Use CWT proofs when requesting mDOC credentials or when the issuer specifically supports cwt proof type in metadata.
Claim Numbers
CWT uses numeric claim keys: 1 (iss), 3 (aud), 6 (iat), 10 (nonce). Same semantics as JWT claims.
Key Binding Methods
The issuer binds the wallet's public key to the credential using one of several methods.
Public key encoded as a DID. Self-contained, no resolution needed.
did:key:z6MkiKq...JWK encoded as a DID. Supports more key types.
did:jwk:eyJrdHkiOiJFQyIsImNydiI6IlAtMjU2Ii...Public key embedded directly in credential as JWK.
"cnf": {
"jwk": {
"kty": "EC",
"crv": "P-256",
"x": "...",
"y": "..."
}
}Presentation with Key Binding
When presenting the credential, the holder signs a proof (KB-JWT for SD-JWT, deviceAuth for mDOC) using the same private key. The verifier checks that:
- Signature is valid
- Signing key matches the bound key in the credential
- Proof includes verifier's nonce (if challenge-response)
Security Considerations
Proper implementation of proof of possession is critical for credential security.