Skip to content

eIDAS Issuer (OpenID4VCI)

EXPERIMENTAL

Like the verifier, the issuer is experimental and gated behind settings.eidas.enabled (routes are 403 until you opt in). It currently scaffolds OpenID4VCI offers and metadata; the credential-signing path is part of the deferred cryptographic core. Responses carry the X-AnvilBase-eIDAS-Experimental: true header and an experimental: true envelope. Do not use for production issuance.

In addition to verifying credentials, an AnvilBase project can issue Verifiable Credentials into users’ EUDI Wallets using OpenID4VCI. This lets you attest facts your application is authoritative about — membership, employment, qualifications, entitlements — as portable credentials the user controls.

Issuance is optional and off by default; enable it in the project’s eIDAS config (which is also the experimental opt-in).

Enable the issuer

Terminal window
curl -X PATCH http://localhost:39001/api/v1/projects/<id>/eidas \
-H "Authorization: Bearer $ANVILBASE_TOKEN" -H "Content-Type: application/json" \
-d '{
"enabled": true,
"issuer": {
"enabled": true,
"credential_types": ["org.example.membership"],
"signing_key_id": "<key-id>"
}
}'
FieldMeaning
issuer.enabledturn issuance on
issuer.credential_typesthe credential types you will issue
issuer.signing_key_idthe key used to sign issued credentials

Issuer metadata

Wallets discover what you can issue from the standard well-known endpoint:

GET /v1/eidas/<project_id>/.well-known/openid-credential-issuer

It advertises the supported credential types, formats, and the issuer’s signing keys.

The issuance flow

1. App ──POST /v1/eidas/{id}/issue──► AnvilBase (create a credential offer)
2. AnvilBase ──► credential offer (offer URI / QR)
3. User's wallet ──► redeems the offer at the issuer endpoint
4. AnvilBase ──► signed Verifiable Credential (SD-JWT-VC or mdoc)
5. Wallet stores the credential; user can later present it anywhere

1. Create a credential offer

Terminal window
curl -X POST "http://localhost:39001/v1/eidas/<project_id>/issue" \
-H "apikey: $SERVICE_KEY" -H "Content-Type: application/json" \
-d '{
"credential_type": "org.example.membership",
"subject_id": "<user-uuid>",
"claims": {
"membership_level": "gold",
"valid_until": "2027-01-01"
}
}'

Issue from trusted server-side code (service_role) — you’re asserting facts about a subject, so the call must be authorized by your application’s logic.

The response is a credential offer (an offer URI you present to the user as a QR code or deep link). Their wallet redeems it and receives the signed credential.

2. Deliver the offer

const { offer_uri } = await createOffer()
showQrCode(offer_uri) // desktop → wallet scans
// or
window.location.href = offer_uri // mobile → opens the wallet

Formats & signing

  • Issued credentials are SD-JWT-VC (supporting selective disclosure) or mdoc, depending on the type.
  • Credentials are signed with the project’s configured signing_key_id. Protect that key as a high-value secret (Encryption → Key management).
  • Because issued credentials carry selective disclosure, the holder can later reveal only specific claims to a verifier.

Lifecycle considerations

  • Expiry — set a sensible validity (valid_until) so credentials don’t outlive the fact they attest.
  • Revocation — design for it (status lists) if you issue long-lived credentials whose validity can change.
  • Audit — every issuance is recorded in the audit log.

Issuer + Verifier together

A project can be both: issue a credential to your users, and elsewhere accept credentials (yours or third parties’) as a verifier. The two halves share the per-project eIDAS config and the same Trust List integration.

Next: Self-Hosting → Overview.