---
id: eu-age-verification
title: Age Verification
description: Issue and verify EU age verification attestations (eu.europa.ec.av.1, ISO mdoc) with OpenID4VCI and OpenID4VP. Prove age over 18 without revealing identity.
hide_title: false
sidebar_label: Age Verification
keywords: [age verification, EU Age Verification, EUDI Wallet age verification, age verification API, eu.europa.ec.av.1, age_over_18, proof of age, mso_mdoc, ISO 18013-5 mdoc, OpenID4VCI, OpenID4VP, DCQL, selective disclosure, age-restricted services, Organisation Wallet, European Business Wallet]
slug: /eu-age-verification/
---

> **Build this with an AI coding agent.** Install the iGrant.io Agent Skills, then ask your agent to build the integration:
>
> ```bash
> npx skills add L3-iGrant/skills
> ```
>
> This page maps to the `igrantio-eu-age-verification` skill. Install just that one with:
>
> ```bash
> npx skills add L3-iGrant/skills -s igrantio-eu-age-verification
> ```

<head>
  <title>Age Verification with EUDI Wallet using OpenID4VC | iGrant.io DevDocs</title>
  <meta name="description" content="Issue and verify EU age verification attestations (eu.europa.ec.av.1, ISO mdoc) with OpenID4VCI and OpenID4VP. Prove age over 18 without revealing identity."/>
</head>

import Link from '@docusaurus/Link';
import NoteBox from '@site/src/components/NoteBox';

This workflow implements the [EU Age Verification solution](https://ageverification.dev/) profile, which defines the age verification attestation as an ISO/IEC 18013-5 mdoc with doctype `eu.europa.ec.av.1` and boolean `age_over_NN` claims. It employs the [OpenID4VCI Issue Credential (In-Time)](/docs/openID4vci-issue-credential-intime/) protocol to issue the attestation and the [OpenID4VP](/docs/openID4vc-send-verify-credentials/) protocol with a [DCQL query](/docs/dcql-overview/) to verify a proof of age. The attestation is issued with selective disclosure enabled, so the holder can prove, for example, being over 18 without revealing any other attribute. The process is illustrated in the diagram below:

![EU Age Verification workflow](./images/ow-eu-age-verification.png)

### Step 1: Get the API Key (Issuer Admin)

To obtain your API key, please contact [support@igrant.io](mailto:support@igrant.io?subject=Request%20API%20Key). Once you have received your API key, enter it in the field below and click the **Set API Key** button to save it for future use.

import { ApiKeyManager } from '@site/src/components/ApiKeyManager';

<ApiKeyManager />

### Step 2: Create Credential Definition (Age Verification Issuer Admin)

Use the code block below to create a credential definition for the age verification attestation in `mso_mdoc` format with doctype `eu.europa.ec.av.1`. You can run it using the **Run** button. Alternatively, execute the API available [here](/docs/openid4vc-api/config-create-digital-wallet-open-id-credential-definition). From the API response, copy the `credentialDefinitionId` and the `id` field from the `credentialDefinitions` array for use in Step 3.

import Step2 from '@site/src/components/AgeVerificationUsecase/Step2';

<Step2
  versionFamily="createCredentialDefinition"
  initialVersionKey="version_01"
  initialFormatKey="mso_mdoc"
/>

### Step 3: Issue Age Verification Attestation (Issuer)

After verifying the age of the individual (e.g. against a national eID, passport or PID), the issuer issues the age verification attestation in in-time (`InTime`) mode with the applicable `age_over_NN` values. When you run Step 2 on this page, the `credentialDefinitionId` and `id` fields below are autofilled automatically (and updated whenever Step 2 is re-run). If you are executing the APIs yourself, replace `<credentialDefinitionId>` and `<id>` with the values obtained in Step 2. Run the code block below using the **Run** button. Alternatively, execute the API available [here](/docs/openid4vc-api/config-digital-wallet-open-id-issue-credential/).

From the API response, note the `CredentialExchangeId`. Toggle the switch provided to render the credential offer as a QR code.

import Step3 from '@site/src/components/AgeVerificationUsecase/Step3';

<Step3
  versionFamily="issueCredential"
  initialVersionKey="version_01"
  initialFormatKey="mso_mdoc"
/>

### Step 4: Receive Attestation (Individual/Holder)

The individual scans the QR code (or opens the `openid-credential-offer://` deeplink) using the [Data Wallet](/docs/data-wallet-overview/) or any other EU Digital Identity Wallet, and receives and stores the age verification attestation.

The issuer can track the issuance lifecycle using the [read credential history API](/docs/openid4vc-api/config-read-digital-wallet-open-id-credential-history) with the `CredentialExchangeId` from Step 3, or alternatively configure [webhooks](/docs/openid4vc-webhooks/) (e.g. the `openid.credential.credential_acked` event) to get notified about issuance lifecycle events.

### Step 5: Create Presentation Definition (Relying Party Admin)

The relying party (e.g. an online service with age-restricted content) creates a presentation definition with a DCQL query requesting the `age_over_18` claim from an `eu.europa.ec.av.1` mdoc. The `label` is the usage purpose shown to the individual when they are asked to share the proof of age. You can request additional `age_over_NN` claims (e.g. `age_over_65` for senior discounts) by adding them to the `claims` array. Run the code block below using the **Run** button. Alternatively, execute the API available [here](/docs/openid4vc-api/config-digital-wallet-open-id-presentation-definition). From the API response, copy the `presentationDefinitionId` for use in Step 6.

<Step2
  versionFamily="createPresentationDefinition"
  initialVersionKey="version_01"
  initialFormatKey="mso_mdoc"
  versionLabel="OpenID4VP Version"
/>

<NoteBox title="Tip:" variant="tip">
Once a presentation definition is created, the <code>presentationDefinitionId</code> can be reused to send multiple verification requests (Step 6).
</NoteBox>

### Step 6: Send Verification Request (Relying Party)

The relying party requests a proof of age from the holder. When you run Step 5 on this page, the `presentationDefinitionId` field below is autofilled automatically (and updated whenever Step 5 is re-run). If you are executing the APIs yourself, replace `<presentationDefinitionId>` with the ID obtained in Step 5. Run the code block below using the **Run** button. Alternatively, execute the API available [here](/docs/openid4vc-api/config-create-digital-wallet-open-id-verification-request-v-3). From the API response, note the `presentationExchangeId`. Toggle the switch provided to render the authorisation request as a QR code.

import Step6 from '@site/src/components/AgeVerificationUsecase/Step6';

<Step6
  versionFamily="sendVerificationRequest"
  initialVersionKey="version_01"
  initialFormatKey="mso_mdoc"
/>

### Step 7: Present Proof of Age (Individual/Holder)

The individual scans the QR code (or opens the `openid4vp://` deeplink) with their wallet, reviews the request and consents to share the `age_over_18` claim. With selective disclosure, only the requested boolean claim is revealed; no birthdate or identity attributes are shared.

The relying party can track the verification using the [read verification history API](/docs/openid4vc-api/config-read-digital-wallet-open-id-verification-history-v-3) with the `presentationExchangeId` from Step 6, or alternatively configure [webhooks](/docs/openid4vc-webhooks/) (e.g. the `openid.presentation.presentation_acked.v3` event) to get notified when the presentation is completed.
