Anonymous Age Credential
The Anonymous Age Credential lets your users prove their age to third parties — for example, that they are over 18 — without sharing any personal information. No name, no ID number, no date of birth. Just a simple yes/no answer to an age question, stored in their digital wallet.
As an issuer, your only job is to create an offer and show the user a QR code or link. The user's wallet and identity provider handle everything else automatically.
What the credential contains
The credential holds a set of age checkpoints. Each one is a simple true/false answer that the user can share independently:
| Age checkpoint | What it means |
|---|---|
age_over_13 | User is 13 or older |
age_over_15 | User is 15 or older |
age_over_16 | User is 16 or older |
age_over_18 | User is 18 or older |
age_over_21 | User is 21 or older |
age_over_23 | User is 23 or older |
age_over_25 | User is 25 or older |
age_over_27 | User is 27 or older |
age_over_60 | User is 60 or older |
age_over_65 | User is 65 or older |
age_over_67 | User is 67 or older |
age_over_69 | User is 69 or older |
The user chooses which checkpoints to share with each verifier. A shop asking "are you over 18?" only sees that one answer — nothing else.
The credential is valid for 6 months from the date it is issued.
Privacy by design
- No personal data is stored or transmitted. The user's date of birth comes from their identity provider's authentication token. The CoreAPI uses it to compute the age checkpoints on the fly and never writes it to the credential.
- Each offer is single-use. The link you create can only be claimed once and expires after 5 minutes if unused.
- The user is not tracked. The credential is tied to the user's own wallet key, not to any identifier held by the issuer.
Who can be an issuer?
Any company or authority that has been approved and onboarded by dewa can issue this credential. In the CoreAPI, approved issuers are called tenants.
Becoming a tenant involves a short approval process where dewa reviews your organization and grants you access. As part of that process you are explicitly enabled for the specific credential types you need — in this case the Anonymous Age Credential. You cannot issue a credential type that has not been enabled for your account.
See Onboarding to get started.
How trust works
When a user's wallet receives a credential, it needs to know the credential is genuine and came from a legitimate source. Here is how that is established:
- dewa vouches for you. Your organization has been reviewed and approved by dewa before you can issue anything.
- Your identity is published openly. Each issuer has a publicly accessible identity document (a DID document) hosted at a well-known URL. It contains your public signing key so anyone can verify credentials you have issued.
- Every credential is digitally signed. The CoreAPI signs each credential with your private key. The user's wallet checks this signature against your published identity before accepting the credential.
This means the user's wallet can independently confirm that the credential came from you — no central registry or intermediary needed.
How to issue a credential
The flow has four steps, but as an issuer you only need to implement step 1. Steps 2–4 are handled automatically by the user's wallet and identity provider.
The age checkpoints are calculated from the date_of_birth claim in the user's identity token — the token they receive when they authenticate with the identity provider connected to your tenant. You do not supply the date of birth yourself.
Step 1 — Create an offer
Call the CoreAPI to create a one-time offer. You need to be authenticated as a tenant.
POST /credential-offer
Authorization: Bearer {your_access_token}
Content-Type: application/json
{
"credential_configuration_id": "dk.e-boks.AnonymousAgeCredential.1",
"offer_expires_at": "2026-04-15T14:00:00Z"
}
| Field | Required | Notes |
|---|---|---|
credential_configuration_id | Yes | Always dk.e-boks.AnonymousAgeCredential.1 for this credential type |
offer_expires_at | Yes | When the offer should expire — must be a future date and time |
The API returns a link:
"openid-credential-offer://?credential_offer_uri=https://issuer.example.com/credential-offer/3fa85f64-..."
Convert this link into a QR code or send it as a deep link to the user. Once they scan or tap it, their wallet takes over and completes the process automatically. The offer expires after 5 minutes if not claimed.
Steps 2–4 — Handled by the wallet and identity provider
The user's wallet fetches the offer details, then authenticates with the identity provider connected to your tenant. The identity provider issues a token that contains the user's date_of_birth. The CoreAPI reads that claim from the token, calculates the age checkpoints, and issues the credential into the user's wallet. No further action is needed from your side.
Common errors
| Situation | What happens |
|---|---|
offer_expires_at is in the past | 400 — request rejected |
| Your access token is missing or expired | 401 — unauthorized |
| Your account is not enabled for this credential type | 403 — contact dewa to have it enabled |
The user's identity token is missing a valid date_of_birth claim | 400 — credential issuance fails; ensure your identity provider includes this claim |
For full error response details see Error Handling.