Why our verifier declares purpose and legal basis in every request

By Olivier Meunier — independent developer building Tessaliq, an EUDI Wallet verifier focused on age verification under the French ARCOM framework.


TL;DR

Privacy policies are text on a page. Nobody reads them. Regulators audit them after the fact, not in real time. Meanwhile, every verification request a service like Tessaliq handles happens at machine speed with no human in the loop to check that the stated purpose matches the actual data asked for.

Tessaliq now attaches a machine-readable Data Privacy Vocabulary (DPV) declaration — purpose, legal basis, retention — to two surfaces:

  • The public policy endpoint GET /v1/policies, so auditors can discover the privacy posture of every policy without running the verifier.
  • Every signed receipt JWT, embedded as JSON-LD, so the posture is cryptographically attested per verification — not a free-text promise on a privacy page.

The declaration follows W3C DPV v2.3, a stable community-group specification that maps cleanly to GDPR Articles 6, 9, 12-14 and 7.

Nothing in this rollout breaks backward compatibility. Old receipts without DPV stay verifiable. New ones carry the fact. The OIDF conformance matrix (24/24 modules passed across 4 immutable plans) is untouched.

This post explains what a DPV-enabled verifier actually does, what it doesn’t do, and why we bothered now rather than later.

What the DPV declaration looks like

For a policy like av_age_18_plus (mdoc-based age verification using the European Commission’s eu.europa.ec.av.1 blueprint profile), the declaration is minimal on purpose:

{
  "@context": [
    "https://w3id.org/dpv#",
    "https://w3id.org/dpv/dpv-gdpr#",
    "xsd:http://www.w3.org/2001/XMLSchema#"
  ],
  "@type": "dpv:PersonalDataHandling",
  "dpv:hasPurpose": { "@id": "dpv:AgeVerification" },
  "dpv:hasLegalBasis": { "@id": "dpv-gdpr:LegalObligation" },
  "dpv:hasDataRetentionPeriod": {
    "@value": "P0D",
    "@type": "xsd:duration"
  },
  "dpv:hasDataController": {
    "@id": "https://api.tessaliq.com"
  },
  "dpv:hasProcessingContext": "eu.europa.ec.eidas2.verifier"
}

In plain English:

  • Purpose: verify that the user is above a given age threshold. Not identity proofing, not profiling, not analytics. dpv:AgeVerification is a specific term in the DPV vocabulary, not a free-text description.
  • Legal basis: LegalObligation (GDPR Art. 6(1)(c)), because the relying party deploying Tessaliq does so to comply with a law — typically the French SREN / ARCOM age verification obligation, or AMLR Article 24, or similar. The RP tells the verifier which specific obligation applies when they configure the policy.
  • Retention: P0D — ISO 8601 duration for zero days, meaning the verifier keeps no claims beyond the request-response cycle. The birth date never survives a request; only the boolean outcome and a receipt hash persist.
  • Data controller: the verifier’s own URI. The RP is a separate controller in the GDPR sense, and they declare their own purpose to their users. The verifier declares its scope narrowly.

Why this matters at the protocol layer

OID4VP 1.0 Final has a transaction_data parameter and a purpose hint that the wallet should display to the user before disclosure. That’s good, but the hint is unstructured — every verifier invents its own string, every wallet renders it differently, and nothing links the hint to a regulatory concept.

DPV fills that gap. dpv:AgeVerification means the same thing to a compliant wallet in France as it does to one in Italy. dpv-gdpr:LegalObligation is a specific enum value mappable to a specific GDPR article. P0D is a parseable duration, not a paragraph.

The long game is simple: a wallet that recognizes DPV can refuse disclosure if the declared purpose is incompatible with the claim being requested. Asking for a full birthdate for an “age verification” purpose is incoherent — a DPV-aware wallet can flag it automatically, before the user has to understand the mismatch.

We’re not there yet. Wallets don’t consume DPV today. But the declaration being embedded in the receipt means the audit trail is clean now, and the infrastructure is ready when wallets catch up.

Why now, not later

Three reasons, in descending order of importance.

First, the regulatory wind direction is clear. The ENISA EUDIW Certification Scheme v0.4.614 went into public consultation on 2 April 2026, closing 30 April. The current draft is silent on purpose declarations, but every adjacent text — GDPR Art. 12-14, the EUDI Architecture Reference Framework v2.8.0, the ISO/IEC 27560:2023 consent record structure, the EHDS HealthDCAT-AP profile — is moving toward structured privacy metadata. When the scheme hardens in late 2026 or 2027, verifiers that already declare purpose and legal basis in a standard vocabulary will be ahead; the ones that don’t will retrofit under pressure.

Second, the cost is near-zero today and rises linearly. Adding a declaration with four fields to a handful of code paths is a day of work when the policies are 13 in number. It will be a week when they’re 50. Doing it while the architecture is small is cheap insurance.

Third, the audit story gets concrete. A regulator or a client asking “what exactly does your verifier do with a request?” can now get an answer that doesn’t require them to trust a privacy page or read the source code. They can ask the verifier itself — GET /v1/policies — and get a structured answer they can parse. That’s the difference between “we say we comply” and “here’s the fact, signed, with a JSON-LD context pointing to the vocabulary that defines the terms.”

What we’re explicitly NOT claiming

Three things worth stating plainly, because DPV is a vocabulary and vocabularies are easy to over-sell.

We’re not claiming the ENISA scheme requires this. It doesn’t — not yet. The v0.4.614 draft does not mention DPV. This is a bet, not a compliance requirement. If the final scheme takes a different path (say, a Tessaliq-incompatible structure), we’ll adapt.

We’re not claiming the wallet will do anything with the declaration today. No mainstream wallet — France Identité, the EU AV app blueprint, Google Wallet, Apple Wallet — currently parses or acts on DPV in an OID4VP request. The declaration sits in the receipt primarily, and in the policy endpoint secondarily. Wallet consumption is future work that depends on wallet vendors adopting the format.

We’re not claiming DPV is settled. It’s a W3C Community Group Specification, which is an order weaker than a Recommendation. The vocabulary has evolved rapidly (we’re on v2.3, released 25 February 2026, with v2.4 in development). We track the spec; if a breaking change lands, we update, and any receipts issued under the old version carry enough context to still be parseable by humans.

Under the hood

For people curious about the code: the declaration is built from a DpvDeclaration object attached to each policy, with a sensible default derivation when no explicit declaration is set. Age-related claims (a birth_date or any age_over_X) map to AgeVerification; everything else maps to IdentityVerification. The defaults push LegalObligation and P0D, which is the honest shape of the Tessaliq verifier’s behavior. Relying parties that want to override — for example to declare LegitimateInterest because they’re running an internal fraud check — can do so at the policy level.

The declaration is serialized to JSON-LD with three contexts: the core DPV vocabulary, the GDPR extension, and XSD datatypes for the retention duration. The JSON-LD shape is stable across the policy endpoint response and the receipt JWT, so a tool that understands one can read the other.

There’s a hidden feature flag, TESSALIQ_DPV_IN_JAR, that will propagate the declaration into the OID4VP authorization request itself via the verifier_info field. It’s disabled by default because we don’t want to risk the OIDF conformance matrix for a field that no wallet currently reads. When wallet support lands, flipping the flag is a one-line change.

Who this is for

Relying parties integrating Tessaliq: you can now point your DPO at GET /v1/policies and have them read the privacy posture of every policy you might activate, directly in a machine-readable format they can cross-reference with your own register of processing activities (RGPD Art. 30).

Auditors and regulators: every receipt issued by Tessaliq now carries the stated purpose and legal basis. You can extract these without asking us — just verify the signature and read the JSON.

Wallet developers: the infrastructure is ready on the verifier side. When you want to surface purpose declarations to users before disclosure, the data is there. We’re happy to interop-test.

Other verifiers: the implementation is small (~130 lines), the vocabulary is open, and we’d rather see a dozen verifiers declaring purpose and legal basis in DPV than one. If you want to adopt the same pattern, the shape we use is in our open-core tessaliq-open repository — copy it, don’t reinvent it.

Next

Three things we’re watching over the coming months.

ENISA’s final EUDIW certification scheme, due to consolidate after the 30 April 2026 deadline. If it lands in favor of structured privacy metadata, DPV will have been a cheap bet. If it lands on something else (an ETSI profile, a custom ISO 27560 subset), we adapt.

Wallet adoption of DPV in the verifier flow. The first wallet to consume verifier_info with DPV content and display something useful to the user will be a notable milestone. We’re happy to be that wallet’s testing partner.

Expansion of the declaration surface. Receipts and the policy endpoint are the first two surfaces. The natural third is the admin UI in our dashboard, where an RP configuring a policy should be able to override the DPV declaration with their own specific legal basis — with validation that flags incoherent choices.

The declaration isn’t the destination. It’s a foundation. Making it automatic and machine-readable means the privacy conversation between a verifier, a wallet, a user, and a regulator can happen at the same speed as the verification itself.


About

Olivier Meunier is an independent developer based in Tiercé, Maine-et-Loire. Tessaliq is a privacy-preserving EUDI Wallet verifier he builds personally to confront EUDI Wallet technical standards with the concrete decisions an implementer has to make. It is a project in the pre-incorporation phase. Open-core: the verifier core is private, peripheral components (Noir circuits, Web SDK, SD-JWT library, shared utilities) are released under MIT license at github.com/Tessaliq/tessaliq-open. Contact: contact [at] tessaliq [dot] com.


← All posts