Credentials

EU age verification attestation (eu.europa.ec.av.1)

The EU age verification attestation is a credential, doctype eu.europa.ec.av.1, that carries nothing but a set of age_over_N booleans. No name, no date of birth, no document number, no portrait. It exists so a service can check someone is old enough without learning anything else about them.

Also called: age attestation, AV attestation, eu.europa.ec.av.1, age_over_18 credential

At a glance

Doctype
eu.europa.ec.av.1
Format
mdoc (ISO 18013-5), as issued today
Contains
age_over_18, plus any optional age_over_NN the issuer chose
Does not contain
Name, date of birth, document number, portrait
Thresholds
18 guaranteed; any others are the issuer's choice
Requested with
DCQL, over OpenID4VP 1.0

What is actually in it

One boolean is guaranteed: age_over_18. The technical specification makes it mandatory in every attestation, allows any number of further age_over_NN booleans as optional extras, and then forbids everything else outright, in the words of Annex A, "a Proof of Age Attestation SHALL NOT include any other attribute". No name, no date of birth, no document number, no portrait, because there is nowhere to put one.

Which extra thresholds you get is therefore up to the issuer. The Commission's test issuer mints thirteen: 13, 15, 16, 18, 21, 23, 25, 27, 28, 40, 60, 65 and 67. That is a useful example and it is not a definition, which is the distinction worth holding on to. We have seen a different set from a different issuer, including thresholds absent from that thirteen. Anyone quoting you a fixed list of age booleans as though the specification defined one has read an issuer, not the spec.

The practical consequence is worth designing around. Build for 18, which every conforming issuer must carry, and treat any other threshold as best effort. Asking for one the holder's credential does not have does not give you a no. It gives you a check that cannot be answered, which is a third outcome and is covered below.

Compare that with the PID, the person identification data credential, which is the wallet's identity document and carries a name, a birth date and more. You can work out whether someone is over 18 from a PID, but doing it means receiving their date of birth. The age attestation exists precisely so you do not have to, and as issued today it is the only EU credential that carries age_over_N without also carrying identity attributes.

Which thresholds you can actually ask for, and where the sources disagree

This is genuinely unsettled, so here is the state of it rather than a tidy answer. What is certain is the first part: the age verification specification mandates age_over_18 and makes every other threshold optional, so which ones a credential carries is the issuer's choice. The Commission's test issuer mints thirteen. The UK's mobile driving licence carries three: 18, 21 and 25.

What is less certain is what happens when you ask for a threshold the credential does not carry. An open issue against the EU reference wallet argues that ISO/IEC 18013-5 clause 7.2.5 requires the wallet to answer with the nearest true attestation above the request, or the nearest false one below, and reports that asking for age_over_16 from an mDL holding only age_over_18 returns nothing at all. The inference would be sound, since age_over_18 being true does settle age_over_16. We have not read the clause ourselves, because ISO/IEC 18013-5 is not published openly, and the issue paraphrases rather than quotes it. So treat it as a reported requirement that at least one major implementation does not currently meet, not as settled behaviour you can design against.

What we do about it. We accept any threshold from 1 to 99, because the claim identifier is age_over_NN and refusing a number for being absent from a list of ours would reject one a wallet can genuinely answer. We treat 18 as guaranteed and everything else as dependent on the holder's issuer and wallet. If a threshold cannot be answered you get a check marked failed with a null result, never a guess in either direction. And if you need a specific threshold for a specific market, tell us and we will find out what actually answers it rather than quoting you a list.

Why this is a stronger privacy claim than a retention promise

Most age verification vendors offer some version of "we delete it afterwards". That is a promise about behaviour, and the only way to audit it is to trust them. This is different in kind. The credential does not contain the data, so there is nothing to delete, nothing to breach, and nothing to produce when someone files a subject access request. You cannot leak what the protocol never sends you.

And because the credential has this property and the vendor does not need to promise it, you do not have to take anyone's word for it. The doctype is public and the specification is published. Which age thresholds an issuer includes is up to the issuer, but what the credential may never contain is not: identity attributes are ruled out by the specification itself, so the privacy property holds no matter who issued it.

The part that trips people up

Asking for a claim is not the same as asking for a value. DCQL, the query language OpenID4VP uses, lets you request the age_over_18 attribute. It does not let you require that the attribute be true. A wallet holding age_over_18 = false can satisfy that request perfectly well, and the response it sends back will verify: the signature is good, the disclosure is genuine, the credential is authentic. The answer is simply no.

So a verifier that treats "verified successfully" as "over 18" is wrong, and it is wrong in the direction that fails open, which is the worst way for an age check to be wrong. You have to read the value that was actually disclosed. We know because we made this mistake in our own implementation and only caught it against a real wallet.

There is a third outcome worth designing for as well. If a credential verifies but did not disclose the boolean you asked for, you do not have a yes and you do not have a no. You have a check that cannot be answered. Folding that into "no" is tempting and it is also wrong: it is a different thing, and it deserves its own state in your data model and your retry logic.

Check one yourself

Reading about it only gets you so far. These are free validators in Tessio.Labs, no signup, and nothing you paste is stored.

Why it matters

If you're writing the integration: read the disclosed boolean. Verification succeeding is a different fact, and give the unanswerable case its own state next to yes and no. Those two decisions are the difference between an age check and an age check that quietly lets everyone through.

If you're choosing a vendor: ask which credential they request. A vendor reading a birth date out of a PID is holding personal data about your users, whatever their retention policy says about it afterwards.

Frequently asked

Does the service learn my date of birth?

Not from this credential, because it doesn't contain one. It holds a set of yes or no answers about age thresholds, and the service receives the one it asked for after you approve it in your wallet.

Can I ask for a threshold other than 18?

Yes. The protocol lets you request any age_over_NN, and whether it can be answered depends on the holder's issuer, because the specification only makes age_over_18 mandatory. Ask for 18 and it works everywhere. Ask for 21 or 65 and it works wherever that issuer chose to include it, and returns an unanswerable check where it did not. Sandboxes and mock wallets tend to mint only age_over_18, so other thresholds are meaningful against a real wallet rather than in a test environment.

Is this the same as a mobile driving licence?

No. An mDL is a driving licence and carries identity attributes including a name and usually a portrait. Both are mdocs, so they travel over the same protocol, but the age attestation is deliberately empty of everything except age answers.

What about users who do not have a wallet?

Then this credential can't answer for them, and you need another route for that traffic. That's a real gap during the rollout, and no verifier can close it, and any vendor telling you the wallet covers all your users today is describing a future rather than the present.

Primary sources

This is a plain language explanation, not legal advice. Specifications and dates in this area move, so check anything you are going to rely on against the primary sources.

Keep reading

Age verification API

Or skip the theory and build against it

Tessio proves someone is over 18 from their EU Digital Identity Wallet and stores no personal data. Signup is open and a test project works as soon as you create one. Tell us what you're building.