France Identitรฉ Partenaires โ OID4VP 1.0 presentation¶
โ Back to the Partenaires app overview
This guide describes how a relying party or verifier can test remote presentations from the France Identitรฉ Partenaires app. It covers age verification and OID4VP 1.0 over the remote presentation flow.
ISO 18013 reference
For live access to the latest published versions of the ISO/IEC 18013 documents, use the OpenWallet Foundation's mdoc.online.
Age verification credential¶
The namespace of the Age Verification credential is eu.europa.ec.av.1.
An Age Verification credential is issued together with the PID.
| Attribute | Value |
|---|---|
age_over_18 |
true |
age_over_21 |
true |
issuing_country |
FR |
expiry_date |
date of the issuance + 3 months |
Age verification integration¶
Use the OID4VP 1.0 flow when a relying party needs to verify that a user is over a required age threshold without collecting the full PID.
End-to-end flow¶
- Create a verification transaction in the relying-party backend.
- Generate a fresh
stateandnonce, and store them server-side with a short expiration time. - Build a signed OID4VP request object with a DCQL query for the age credential.
- Publish the request object at an HTTPS
request_uri. - Render a QR code or deep link using the
openid4vp://invocation. - The user scans the request with France Identitรฉ and approves the presentation.
- France Identitรฉ posts the encrypted authorization response to the
response_uri. - The relying-party backend decrypts the response, validates
state, validates the wallet presentation, and extracts the age claim. - The relying-party backend returns an age-verification decision to the end-application.
sequenceDiagram
participant RP as Relying party
participant User as User device
participant Wallet as France Identitรฉ
RP->>RP: Create transaction, nonce, state
RP->>User: Show QR code / openid4vp deep link
User->>Wallet: Scan or open request
Wallet->>RP: Fetch request object from request_uri
Wallet->>User: Request consent
Wallet->>RP: POST encrypted direct_post.jwt response
RP->>RP: Decrypt, validate, verify mdoc, decide
RP->>User: Continue or deny age-gated flow
Recommended age-verification query¶
For an over-18 check, request only the Age Verification credential:
| Field | Value |
|---|---|
| Credential namespace | eu.europa.ec.av.1 |
| Doctype | eu.europa.ec.av.1 |
| Claim | age_over_18 |
| Expected value | true |
| Format | mso_mdoc |
| Holder binding | Required |
For data minimization, request age_over_18 instead of PID attributes such as name, birth date, or portrait. Set intent_to_retain according to the applicable legal basis and retention policy.
OID4VP 1.0 integration profile¶
France Identitรฉ supports OID4VP 1.0 remote presentation with signed request objects, DCQL queries, encrypted authorization responses, and the direct_post.jwt response mode.
Verifier responsibilities¶
The verifier backend is responsible for the complete presentation lifecycle:
- Serve the signed request object over HTTPS from the
request_uri. - Bind each request to a single server-side transaction using
stateandnonce. - Accept the authorization response only on the registered
response_uri. - Decrypt the
direct_post.jwtresponse with the private key matching the public key advertised inclient_metadata.jwks. - Reject replayed, expired, or unknown
statevalues. - Verify the mdoc issuer chain against the correct France Identitรฉ environment certificate.
- Verify the mdoc device signature / holder binding.
- Return a business decision from the verified claim, not from client-side data.
The response_uri endpoint is expected to accept only HTTPS POST requests and to return a minimal success or error status. Decrypted claims, tokens, and certificate internals must not be exposed in browser-visible error messages.
Request URI methods¶
The wallet supports both request object retrieval methods:
request_uri_method=getrequest_uri_method=post
When request_uri_method=post is present, the wallet retrieves the request object by sending an HTTP POST request to the request_uri.
Invocation example¶
openid4vp://?client_id=x509_san_dns%3Aapi.playground.france-identite.gouv.fr&request_uri=https%3A%2F%2Fapi.playground.france-identite.gouv.fr%2Fv2%2Fidakto%2Fopenid4vp%2Fvp1%2Fauthorization%2Frequest.jwt%2FW6cM6C9VCKoCMp27bjm7fg&request_uri_method=post
Request object profile¶
| Claim | Expected value |
|---|---|
aud |
Wallet-facing audience, for example https://api.playground.france-identite.gouv.fr |
iss |
Same verifier identifier as client_id |
client_id |
x509_san_dns:<verifier-dns-name> |
response_type |
vp_token |
response_mode |
direct_post.jwt |
response_uri |
HTTPS endpoint receiving the encrypted authorization response |
nonce |
Fresh, high-entropy value generated per transaction |
state |
Opaque transaction state generated by the verifier |
client_metadata.authorization_encrypted_response_alg |
ECDH-ES, others are supported |
client_metadata.authorization_encrypted_response_enc |
A256GCM, others are supported |
client_metadata.jwks |
Verifier encryption keys. |
client_metadata.vp_formats_supported.mso_mdoc |
Supported mdoc issuer-auth and device-auth algorithms |
dcql_query |
DCQL presentation query. The reference request asks for eu.europa.ec.av.1 / age_over_18. |
The verifier is not whitelisted by France Identitรฉ for this OID4VP 1.0 flow. Trust is established from the request object and the verifier certificate material, including the x509_san_dns client identifier.
Request object validation checklist¶
Before a request is displayed to the user, verify that:
client_idandissuse the samex509_san_dnsidentifier.- The DNS name in
client_idmatches the verifier signing certificate SAN. request_uriandresponse_uriuse HTTPS.nonceis unique per transaction and cannot be reused.stateis high entropy and mapped to one pending transaction.response_modeisdirect_post.jwt.client_metadata.jwkscontains the encryption public key corresponding to the response decryption private key.- The DCQL query requests only the claims required for the age decision.
Minimal age-verification DCQL example¶
{
"credentials": [
{
"id": "age_over_18",
"format": "mso_mdoc",
"meta": {
"doctype_value": "eu.europa.ec.av.1"
},
"claims": [
{
"path": [
"eu.europa.ec.av.1",
"age_over_18"
],
"intent_to_retain": true
}
],
"multiple": false,
"require_cryptographic_holder_binding": true
}
]
}
Authorization response handling¶
France Identitรฉ sends the presentation result to the response_uri using direct_post.jwt. Treat the incoming value as an encrypted authorization response, not as a plain JSON body.
At a minimum, the response endpoint must:
- Parse the posted
responseparameter. - Decrypt the JWE using the verifier private key associated with the request object's
jwksentry. - Validate
stateagainst the transaction created before the QR code or deep link was displayed. - Validate
noncebinding inside the presentation according to the OID4VP and mdoc verification rules. - Extract the
vp_token. - Verify the mdoc issuer authentication and device authentication.
- Validate the issuer certificate chain against the right environment certificate in the Issuer certificates and trust material section.
- Read
eu.europa.ec.av.1.age_over_18.
The verifier is expected to fail closed. If decryption, state validation, nonce validation, certificate validation, holder binding, or claim extraction fails, the age-verification decision must be negative.
Reference request object¶
The following request object illustrates the supported OID4VP 1.0 profile.
OID4VP 1.0 request object payload
{
"aud": "https://api.playground.france-identite.gouv.fr",
"client_id": "x509_san_dns:api.playground.france-identite.gouv.fr",
"client_metadata": {
"authorization_encrypted_response_alg": "ECDH-ES",
"authorization_encrypted_response_enc": "A256GCM",
"client_uri": "https://api.playground.france-identite.gouv.fr/v2/idakto/openid4vp",
"contacts": [
""
],
"jwks": {
"keys": [
{
"alg": "ECDH-ES",
"crv": "BP-320",
"kid": "74947646-4c9f-11f1-9044-c69e37a7b878",
"kty": "EC",
"use": "enc",
"x": "CEYs0pvwYF3SSTM6aGsn0RtXH57yigpKxXVaKenXVh4_JZsLAo-lew",
"y": "F-oFm59AccGVRQsQgo37x_g1ktE-MgbIbybKWyt-eAgfmFvyboHZ_g"
},
{
"alg": "ECDH-ES",
"crv": "BP-384",
"kid": "74954a2d-4c9f-11f1-9044-c69e37a7b878",
"kty": "EC",
"use": "enc",
"x": "eSx71sD518B8TEc-7E7DG9xmWO44TWG-dapyYLROR6Y31XXrESD6ydGLpHb79tFu",
"y": "do-4v0YFdGFaCQqC2eMYUA71Qo4WmwDnbr7F8ZC_PGU8R75jgYcHQyhPXntPs4If"
},
{
"alg": "ECDH-ES",
"crv": "BP-512",
"kid": "74962304-4c9f-11f1-9044-c69e37a7b878",
"kty": "EC",
"use": "enc",
"x": "R1vFUbydFHaW2NAp93QbXQgJ6gaTeLHYv-uLXu79emOGtY3ObLWINEuVUNpQChbrRa-FDRcxQDt9KHbQcic05A",
"y": "lUVYKHB2oAysg77P_4BAbxrDLbGj1vF90aB548Ra97Whz0bwgnp0F4WCYaSrpHQAffSNXjP93zhHzW6iB6ERZQ"
},
{
"alg": "ECDH-ES",
"crv": "P-256",
"kid": "74962680-4c9f-11f1-9044-c69e37a7b878",
"kty": "EC",
"use": "enc",
"x": "lvLAevmcYq4ZjPqPccKaJsZj2Vel4ufyKLzW820JQKE",
"y": "se-XRsppIRI7OSN_-03N4MWQC_ZAEzmaPnb5UPibrwE"
},
{
"alg": "ECDH-ES",
"crv": "P-384",
"kid": "74963099-4c9f-11f1-9044-c69e37a7b878",
"kty": "EC",
"use": "enc",
"x": "LMcUEdJQud2tIFxTMw7Q7vtU4aWrlyBczGvhQa2uKU_MzYPQah13myUZayZsr_7V",
"y": "sY3ghVJklRJoLMw6wQmaZvFDUoHxok_U6J4Z3Sie49L7jNB9ymqrPO8BNo56SWaE"
},
{
"alg": "ECDH-ES",
"crv": "P-521",
"kid": "749649b6-4c9f-11f1-9044-c69e37a7b878",
"kty": "EC",
"use": "enc",
"x": "ANr0_-kfE2v73zsyL2wYUpdHlajnRq5ITJfcLd-cfJjsjHe8S6gVXXjcTpxxdvdVAY7wvv4gi-3Sxf3iBNlJh9pe",
"y": "AKlkOMkeLbG1VE4GGRmbUkarcelummfRsgMmoe6BkUjXOLyb6oAfLOAWQ-qgFssssvA7axHy-hdxnQx3vA2R9Klx"
},
{
"alg": "ECDH-ES",
"crv": "BP-256",
"kid": "7496abb0-4c9f-11f1-9044-c69e37a7b878",
"kty": "EC",
"use": "enc",
"x": "Bf1Bf8eSvZoR-S6QX1Hmcca-nkxh5yf8nh0QCjf8M80",
"y": "SQOBZ9_IgblK-JgaJiQgsE4RmkaWl-qtlKnNDyqx1SY"
}
]
},
"response_types": [
"vp_token"
],
"software_id": "64c1db22-b726-468a-aaaa-24fc9e632233",
"software_version": "1.1.0-SNAPSHOT",
"vp_formats_supported": {
"dc+sd-jwt": {
"kb-jwt_alg_values": [
"ES256",
"ES384",
"ES512"
],
"sd-jwt_alg_values": [
"ES256",
"ES384",
"ES512"
]
},
"mso_mdoc": {
"deviceauth_alg_values": [
"ES256",
-7,
"ESP256",
-9,
"ES384",
-35,
"ESP384",
-51,
"ES512",
-36,
"ESP512",
-52,
"ESB256",
-261,
"ESB320",
-262,
"ESB384",
-263,
"ESB512",
-264,
-65537,
-65538,
-65539,
-65542,
-65543,
-65544,
-65545
],
"issuerauth_alg_values": [
"ES256",
-7,
"ESP256",
-9,
"ES384",
-35,
"ESP384",
-51,
"ES512",
-36,
"ESP512",
-52,
"ESB256",
-261,
"ESB320",
-262,
"ESB384",
-263,
"ESB512",
-264
]
}
}
},
"dcql_query": {
"credentials": [
{
"claims": [
{
"intent_to_retain": true,
"path": [
"eu.europa.ec.av.1",
"age_over_18"
]
}
],
"format": "mso_mdoc",
"id": "A3DiaCvAGOGD6UypKzi08w",
"meta": {
"doctype_value": "eu.europa.ec.av.1"
},
"multiple": false,
"require_cryptographic_holder_binding": true
}
]
},
"iss": "x509_san_dns:api.playground.france-identite.gouv.fr",
"nonce": "8l2Kep-ga_lU_Qmj-4Fv-1ZIu7TMcsqfTabKLDHOVgs",
"response_mode": "direct_post.jwt",
"response_type": "vp_token",
"response_uri": "https://api.playground.france-identite.gouv.fr/v2/idakto/openid4vp/vp1/authorization/response.jwt",
"state": "cPsfZvOptPHUJSxTW8eTNts_mphcAnuvhv5TDgqM-lc"
}
Testing remote presentation (ISO 18013-7 Annex B and OID4VP 1.0)¶
- From the application home screen, tap the blue button at the bottom of the screen.
- Scan the presentation request QR code.
A remote verifier for online age verification is available in the playground: proof of age verifier.
Reference verifiers are also available:
Technical references¶
The following references are relevant for implementers integrating France Identitรฉ into an age-verification relying-party flow:
| Reference | Scope |
|---|---|
| EU Age Verification profile | Age-verification profile and implementation guidance. |
| OpenID for Verifiable Presentations 1.0 | OID4VP 1.0 protocol specification. |
| OpenID4VC High Assurance Interoperability Profile 1.0 | HAIP 1.0 profile for high-assurance OpenID4VC interoperability. |
| ISO/IEC 18013 working documents | ISO/IEC 18013 working documents, including mobile driving licence and mdoc-related material. |
| ISO/IEC 18013-7 Annex B protocol PDF | Local copy of the ISO/IEC 18013-7 Annex B protocol material used by the playground documentation. |