SecureQR v2.0
The second version of SecureQR exists to simplify the reconstruction and verification process of SecureQR presentations. Changes include new URI-based QR frame-data, compression of the Verifiable Credential payload and better alignment with standards such as SD-JWT (RFC9901).
Security Considerations
Because SecureQR codes are targeted towards simple device-to-device, the wallet and verifier
are not able to exchange a nonce. Instead the verifier relies on short lived presentations,
which require the phone and verifier clocks to be sufficiently synchronized. To prevent misuse
the lifetime of a presentation MUST be less than 15 minutes (exp - iat <= 900).
The verifier MAY temporarily store the wallet key ID and or jti, that is
bound to the Verifiable Credential to identify copied credentials. The verifier must
verify both presentation- and VC signature as well as the revocation list status, as
specified by OpenID4VP 1.0
and W3C VCDM 2.0.
A full OpenID4VP flow is RECOMMENDED for all use-cases with strict security requirements.
High-level overview

Decoding / Verification
Implement the following steps in order to decode and verify SecureQR presentations:
- Parse all QR Code URI frames
- Assert all "id"s match
- Sort frames according to "n"
- Concat QR Codes' chunk data ("d") as Frame Payload
- Decompress Frame Payload using zlib and parse JSON
- Combine "vc1", "vc2" and "vc3" strings to create VC
- vc1 + "." + base64urlEncode(vc2) + "." + vc3
- Extract Holder Key from cnf.jwk property of VC payload
- Verify key binding signature using Holder Key (RFC9901)
- Assert nbf < iat < exp of key binding
- Complete verification of VC as specified by OID4VP
- Including but not limited to VC signature, iss, exp, iat, nbf
Appendix
Example SecureQR sequence
| Frame nr. | QR code |
|---|---|
| 0 |
|
| 1 |
|
| 2 |
|
| 3 |
|
Example SecureQR payload
Frame payload after decompression:
{
vc1: "eyJraWQiOiJkaWQ6d2ViOmRlbW8uYWRkLWlkLmRldiNodFFaWXIiLCJ0eXAiOiJkYytzZC1qd3QiLCJhbGciOiJFUzI1NiJ9",
vc2: '{"nbf":1770133791,"vct":"DemoCredential","_sd_alg":"sha-256","iss":"did:web:demo.add-id.dev","cnf":{"jwk":{"kty":"EC","crv":"P-256","x":"2PtPyYUN-JB_BJOuEP2FdS-3kH8OOiF0rUUkQ9TwcbM","y":"sOd2D4QBE6Dk_Q7m4kP_9EGZu_nMwNrWy6mZ31aRPJc"}},"exp":1927900191,"vc":{"@context":["https://www.w3.org/2018/credentials/v1"],"type":["VerifiableCredential","DemoCredential"],"credentialSubject":{"id":"did:key:z2dmzD81cgPx8Vki7JbuuMmFYrWPgYoytykUZ3eyqht1j9KbnYYhRGsVD5jshyJMpdtcAcJ2uhRw9c7gCKSrhoPFFndrzL2YqgLx3z3EJwtuJnt5rQVcBTG5ayTwtj8F5Ebj2ifLs5GmQtUd8ozFwENmYmYetPa9BBZLUNQgKh5QCSjBUx","_sd":["a57NKmuEMlNHcgqTHEGZI5eIEfj-bHl_6op58LNVEDI","Apq5uAgAHXwzkE7wFztFCw2q2YYTSJRz0JCojFW-jQg","JYIHcpbyIyGBQKwPDIuNzO26ivYzFfLtlZ-TOTIbh9Y"]},"credentialStatus":{"id":"https://add-id.dev/credential-status/2","type":"BitstringStatusListEntry","statusPurpose":"revocation","statusListIndex":28223805,"statusListCredential":"https://add-id.dev/credential-status/2","statusSize":1},"credentialSchema":{"id":"https://add-id.dev/v1/registry/schemas/d067196b-e4f1-46a5-958d-ac57d3ededb4","type":"FullJsonSchemaValidator2021"},"issuer":"did:web:demo.add-id.dev","issued":"2026-02-03T15:49:51.1545126+00:00","issuanceDate":"2026-02-03T15:49:51.1545126+00:00","validFrom":"2026-02-03T15:49:51.1545126+00:00","validUntil":"2031-02-03T15:49:51.1545126+00:00","expirationDate":"2031-02-03T15:49:51.1545126+00:00"},"iat":1770133791,"jti":"be626f05-679a-4bc7-94b6-588205eed96f"}',
vc3: "4XNDJg71L6eCtXg4KTorWJDkfYhqCM9LSmIS-X7yQsGPrS5BafkdcLUccSOGKhwldqSiqOcK2MOta6TRfvjivg~WyJlNTdBdkh4R1BUVzNMWnVPdXVyam9RIiwiYWdlIiwxMl0~eyJ0eXAiOiJrYitqd3QiLCJhbGciOiJFUzI1NiJ9eyJpYXQiOjE3NzAyODIyMDQsIm5iZiI6MTc3MDI4MjIwNCwiZXhwIjoxODMzMzk2MDU1LCJhdWQiOiIuLi4iLCJub25jZSI6Ii4uLiIsInNkX2hhc2giOiJrbHk3SUhfcUhRT1ZSTWViTm1yRVk3N0RqZlpsUzd6T3hMblJPT29QbXpNIn0PO-KJR4Wh5zMtks3CUNqbB6xv56H4tPvChB9YKekf8pP4FkfADsTp2J2_Kj-S0jDUy4xpa9n1y0LdgEBlKoKnw"
}
SD-JWT presentation after reassembly:
eyJraWQiOiJkaWQ6d2ViOmRlbW8uYWRkLWlkLmRldiNodFFaWXIiLCJ0eXAiOiJkYytzZC1qd3QiLCJh
bGciOiJFUzI1NiJ9.eyJuYmYiOjE3NzAxMzM3OTEsInZjdCI6IkRlbW9DcmVkZW50aWFsIiwiX3NkX2F
sZyI6InNoYS0yNTYiLCJpc3MiOiJkaWQ6d2ViOmRlbW8uYWRkLWlkLmRldiIsImNuZiI6eyJqd2siOns
ia3R5IjoiRUMiLCJjcnYiOiJQLTI1NiIsIngiOiIyUHRQeVlVTi1KQl9CSk91RVAyRmRTLTNrSDhPT2l
GMHJVVWtROVR3Y2JNIiwieSI6InNPZDJENFFCRTZEa19RN200a1BfOUVHWnVfbk13TnJXeTZtWjMxYVJ
QSmMifX0sImV4cCI6MTkyNzkwMDE5MSwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3J
nLzIwMTgvY3JlZGVudGlhbHMvdjEiXSwidHlwZSI6WyJWZXJpZmlhYmxlQ3JlZGVudGlhbCIsIkRlbW9
DcmVkZW50aWFsIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImlkIjoiZGlkOmtleTp6MmRtekQ4MWNnUHg
4VmtpN0pidXVNbUZZcldQZ1lveXR5a1VaM2V5cWh0MWo5S2JuWVloUkdzVkQ1anNoeUpNcGR0Y0FjSjJ
1aFJ3OWM3Z0NLU3Job1BGRm5kcnpMMllxZ0x4M3ozRUp3dHVKbnQ1clFWY0JURzVheVR3dGo4RjVFYmo
yaWZMczVHbVF0VWQ4b3pGd0VObVltWWV0UGE5QkJaTFVOUWdLaDVRQ1NqQlV4IiwiX3NkIjpbImE1N05
LbXVFTWxOSGNncVRIRUdaSTVlSUVmai1iSGxfNm9wNThMTlZFREkiLCJBcHE1dUFnQUhYd3prRTd3Rnp
0RkN3MnEyWVlUU0pSejBKQ29qRlctalFnIiwiSllJSGNwYnlJeUdCUUt3UERJdU56TzI2aXZZekZmTHR
sWi1UT1RJYmg5WSJdfSwiY3JlZGVudGlhbFN0YXR1cyI6eyJpZCI6Imh0dHBzOi8vYWRkLWlkLmRldi9
jcmVkZW50aWFsLXN0YXR1cy8yIiwidHlwZSI6IkJpdHN0cmluZ1N0YXR1c0xpc3RFbnRyeSIsInN0YXR
1c1B1cnBvc2UiOiJyZXZvY2F0aW9uIiwic3RhdHVzTGlzdEluZGV4IjoyODIyMzgwNSwic3RhdHVzTGl
zdENyZWRlbnRpYWwiOiJodHRwczovL2FkZC1pZC5kZXYvY3JlZGVudGlhbC1zdGF0dXMvMiIsInN0YXR
1c1NpemUiOjF9LCJjcmVkZW50aWFsU2NoZW1hIjp7ImlkIjoiaHR0cHM6Ly9hZGQtaWQuZGV2L3YxL3J
lZ2lzdHJ5L3NjaGVtYXMvZDA2NzE5NmItZTRmMS00NmE1LTk1OGQtYWM1N2QzZWRlZGI0IiwidHlwZSI
6IkZ1bGxKc29uU2NoZW1hVmFsaWRhdG9yMjAyMSJ9LCJpc3N1ZXIiOiJkaWQ6d2ViOmRlbW8uYWRkLWl
kLmRldiIsImlzc3VlZCI6IjIwMjYtMDItMDNUMTU6NDk6NTEuMTU0NTEyNiswMDowMCIsImlzc3VhbmN
lRGF0ZSI6IjIwMjYtMDItMDNUMTU6NDk6NTEuMTU0NTEyNiswMDowMCIsInZhbGlkRnJvbSI6IjIwMjY
tMDItMDNUMTU6NDk6NTEuMTU0NTEyNiswMDowMCIsInZhbGlkVW50aWwiOiIyMDMxLTAyLTAzVDE1OjQ
5OjUxLjE1NDUxMjYrMDA6MDAiLCJleHBpcmF0aW9uRGF0ZSI6IjIwMzEtMDItMDNUMTU6NDk6NTEuMTU
0NTEyNiswMDowMCJ9LCJpYXQiOjE3NzAxMzM3OTEsImp0aSI6ImJlNjI2ZjA1LTY3OWEtNGJjNy05NGI
2LTU4ODIwNWVlZDk2ZiJ9.4XNDJg71L6eCtXg4KTorWJDkfYhqCM9LSmIS-X7yQsGPrS5BafkdcLUccS
OGKhwldqSiqOcK2MOta6TRfvjivg~WyJlNTdBdkh4R1BUVzNMWnVPdXVyam9RIiwiYWdlIiwxMl0~eyJ
0eXAiOiJrYitqd3QiLCJhbGciOiJFUzI1NiJ9.eyJpYXQiOjE3NzAyODIzMjMsIm5iZiI6MTc3MDI4Mj
MyMywiZXhwIjoxODMzMzk2MTc0LCJhdWQiOiIuLi4iLCJub25jZSI6Ii4uLiIsInNkX2hhc2giOiJrbH
k3SUhfcUhRT1ZSTWViTm1yRVk3N0RqZlpsUzd6T3hMblJPT29QbXpNIn0.8K-murMMLBZdRscUHbk6gz
RFqBijEZXm1EUFWaydaMDVRWH_491S3f2-OMBNMQsXFKFgzGY2AWGnuHzBl1fAGg
SD-JWT decoded
Header:
{
"alg": "ES256",
"kid": "did:web:demo.add-id.dev#htQZYr",
"typ": "dc+sd-jwt"
}
Payload:
{
"_sd_alg": "sha-256",
"cnf": {
"jwk": {
"crv": "P-256",
"kty": "EC",
"x": "2PtPyYUN-JB_BJOuEP2FdS-3kH8OOiF0rUUkQ9TwcbM",
"y": "sOd2D4QBE6Dk_Q7m4kP_9EGZu_nMwNrWy6mZ31aRPJc"
}
},
"exp": 1927900191, // Feb 03 2031 15:49:51 GMT+0000
"iat": 1770133791, // Feb 03 2026 15:49:51 GMT+0000
"iss": "did:web:demo.add-id.dev",
"jti": "be626f05-679a-4bc7-94b6-588205eed96f",
"nbf": 1770133791, // Feb 03 2026 15:49:51 GMT+0000
"vc": {
"@context": [
"https://www.w3.org/2018/credentials/v1"
],
"credentialSchema": {
"id": "https://add-id.dev/v1/registry/schemas/d067196b-e4f1-46a5-958d-ac57d3ededb4",
"type": "FullJsonSchemaValidator2021"
},
"credentialStatus": {
"id": "https://add-id.dev/credential-status/2",
"statusListCredential": "https://add-id.dev/credential-status/2",
"statusListIndex": 28223805,
"statusPurpose": "revocation",
"statusSize": 1,
"type": "BitstringStatusListEntry"
},
"credentialSubject": {
"_sd": [
"a57NKmuEMlNHcgqTHEGZI5eIEfj-bHl_6op58LNVEDI",
"Apq5uAgAHXwzkE7wFztFCw2q2YYTSJRz0JCojFW-jQg",
"JYIHcpbyIyGBQKwPDIuNzO26ivYzFfLtlZ-TOTIbh9Y"
],
"id": "did:key:z2dmzD81cgPx8Vki7JbuuMmFYrWPgYoytykUZ3eyqht1j9KbnYYhRGsVD5jshyJMpdtcAcJ2uhRw9c7gCKSrhoPFFndrzL2YqgLx3z3EJwtuJnt5rQVcBTG5ayTwtj8F5Ebj2ifLs5GmQtUd8ozFwENmYmYetPa9BBZLUNQgKh5QCSjBUx"
},
"expirationDate": "2031-02-03T15:49:51.1545126+00:00",
"issuanceDate": "2026-02-03T15:49:51.1545126+00:00",
"issued": "2026-02-03T15:49:51.1545126+00:00",
"issuer": "did:web:demo.add-id.dev",
"type": [
"VerifiableCredential",
"DemoCredential"
],
"validFrom": "2026-02-03T15:49:51.1545126+00:00",
"validUntil": "2031-02-03T15:49:51.1545126+00:00"
},
"vct": "DemoCredential"
}
Key Binding JWT decoded
Header
{
"typ": "kb+jwt",
"alg": "ES256"
}
Payload
{
"iat": 1770282323, // Feb 05 2026 09:05:23 GMT+0000
"nbf": 1770282323, // Feb 05 2026 09:05:23 GMT+0000
"exp": 1833396174, // Feb 05 2028 20:42:54 GMT+0000
"aud": "...",
"nonce": "...",
"sd_hash": "kly7IH_qHQOVRMebNmrEY77DjfZlS7zOxLnROOoPmzM"
}



