Technical
Overview
veryf.eu is a compliant Relying Party integration layer for the EU Age Verification Blueprint (published April 2026). Your service requests a proof of age. The user's Age Verification App (AVI) responds with an ISO mDoc device response. Your database receives one boolean — not the underlying personal data, because the underlying personal data was never in the attestation.
How it works
veryf.eu mediates between your service (the relying party) and the user's EUDI Wallet using the OpenID for Verifiable Presentations (OpenID4VP) protocol. The flow has three participants:
I. The Issuer
A government body or eIDAS-qualified trust service provider that issued the user's EUDI Wallet credential. Each attribute in the credential is committed as a cryptographic hash. This happens once, offline, before your service is ever involved.
II. The Wallet
The user's EUDI-compliant wallet application. It holds the full credential but only discloses the specific claims your verification request asks for. All other attributes remain hashed and never transmit.
III. Your service
You send a verification request specifying which claim to check. veryf.eu generates the OpenID4VP presentation request, handles the wallet exchange, verifies the cryptographic proof against the issuer's trust anchor, and delivers a verified result to your webhook.
Compliance context
verif.eu is built specifically for the eIDAS 2.0 regulatory landscape:
Verification flow
A complete verification exchange takes under one second end-to-end.
1. Your server → POST /v1/sessions { claim: "age_over_18" }
2. veryf.eu → Returns session_id + av:// deep_link for AVI
3. Your frontend → Displays QR or redirects to av:// link
4. User AVI → Presents ISO mDoc device response (eu.europa.ec.av.1)
5. veryf.eu → Verifies Issuer-signed MSO against AP trust anchor
6. veryf.eu → POST to your webhook_url
7. Your server → Receives { verified: true, claims: { age_over_18: true } }
Steps 4–7 are invisible to your frontend. The webhook fires once the proof is validated.
Webhook response
veryf.eu delivers a single POST to the webhook_url you supply when creating a session. The payload is intentionally minimal.
{
"session_id": "sess_01JKPQR...",
"verified": true,
"claims": {
"age_over_18": true
},
"issuer": "https://eidas.gov.ee",
"verified_at": 1748563247
}
// No name. No birth date. No document number.
// This is the entire payload.
| Field | Type | Description |
|---|---|---|
| session_id | string |
The session identifier returned when you created the verification request |
| verified | boolean |
Whether the proof was cryptographically valid and the issuer trust anchor confirmed |
| claims | object |
Key-value map of the disclosed claims. Contains only what was requested |
| issuer | string |
The trust anchor URL of the credential issuer. Publicly known — not personal data |
| verified_at | unix timestamp |
When the proof was validated, in seconds |
Supported claims
The following claims are supported in early access. The claim set expands as issuer integrations are added.
| Claim | Returns | Regulatory mapping |
|---|---|---|
| age_over_18 | boolean |
DSA Art. 28, MiCA onboarding, EU Blueprint (eu.europa.ec.av.1) |
| age_over_NN | boolean |
Any integer age threshold — same attestation namespace |
| Per EU Age Verification Blueprint spec: the Proof of Age Attestation (doc type eu.europa.ec.av.1) SHALL NOT include any other attribute. nationality, eu_resident, and similar claims are not valid claims in this attestation format. EUDI Wallet credentials support those via separate attestation types. | ||
Error codes
| Code | Meaning |
|---|---|
| proof_invalid | Cryptographic proof failed to verify against the issuer trust anchor |
| nonce_expired | Session nonce expired (sessions are valid for 10 minutes) |
| nonce_replayed | Nonce was already consumed — replay attempt blocked |
| issuer_untrusted | Credential issuer not in the eIDAS qualified trust service list |
| claim_not_disclosed | User wallet did not disclose the requested claim |
| holder_rejected | User declined to present the credential |
Security model
veryf.eu implements the EU Age Verification Blueprint presentation protocol. Attestations are ISO mDoc format (ISO/IEC 18013-5), delivered via W3C Digital Credentials API (primary) or OpenID4VP direct_post (fallback). Key security properties:
Issuer-signed MSO
Every attestation is issued with a Mobile Security Object (MSO) signed by the Attestation Provider using ES256 (P-256 ECDSA). veryf.eu verifies this signature against the AP's published key on the EU Trusted List (ETSI TS 119 612) before accepting any response. A forged or tampered attestation will fail at this step.
Device authentication
The AVI generates a device authentication signature for each presentation, binding the session transcript and nonce. This is a property of the ISO mDoc device response structure — not a separate JWT. It prevents any party from replaying a captured presentation in a different session context.
Nonce binding
Each session generates a single-use nonce included in the session transcript. The nonce is consumed on first use. Any attempt to replay the presentation after the nonce is consumed returns nonce_replayed.
Transport encryption
Responses over the W3C Digital Credentials API are encrypted using HPKE (RFC 9180). OpenID4VP fallback uses TLS 1.3. No credential material is transmitted in plaintext at any point.
Selective disclosure hash matching
The issuer commits all credential attributes as salted hashes at issuance. When the wallet discloses a claim, veryf.eu verifies that the disclosed value matches the corresponding hash in the issuer-signed credential. This means a wallet cannot disclose a modified or fabricated value even for a claim the issuer originally signed.
Early access
API credentials, sandbox environment, and integration support are available to early access partners. The full API reference is issued on access confirmation.
veryf.eu is in closed early access. API keys are issued directly after a short technical conversation.
Request access