<!-- Generated from prerendered index.html. HTML SHA-256: 05f90a8345dcd71aeb6525c36f71f515de66e6ba7a6bfbd6ffe3fdb07a1509be -->

# 03 · Identification auprès d'un service avec le portefeuille

> Section autonome du guide [eIDAS 2, échange par échange](https://signature.codethelaw.eu/).

Spécifié, déploiement fin 2026

Protocole final : OpenID4VP 1.0 (9 juillet 2025), profilé par HAIP 1.0. Enregistrement des parties utilisatrices : règlement d'exécution (UE) 2025/848 ; la validation des certificats d'enregistrement par le portefeuille est différée au 11 août 2028 par le règlement 2026/1731.

Le service demande des attributs précis, le portefeuille vérifie qui demande, l'utilisateur consent, et le portefeuille ne révèle que les attributs demandés, liés à la transaction par une signature de sa clé. Flux représenté : HAIP, redirection sur le même appareil.

## 3.1 Construire la demande signée (JAR)

Service utilisateur → Service utilisateur · Requête signée

### Entrée

Ce que le service veut savoir, et ce qui l'identifie.

**TEXTE**

```text
Attributs nécessaires : nom, prénom, date de naissance
Identité du service : certificat d'accès X.509 délivré dans le cadre de l'enregistrement
```

### Traitement

1.  Le service génère un nonce aléatoire, un state et une clé éphémère P-256 pour chiffrer la réponse.
2.  Il exprime sa demande en DCQL : la nationalité n'étant pas demandée, elle ne sera pas divulguée.
3.  Il signe l'objet de requête avec la clé de son certificat d'accès ; HAIP impose le préfixe x509\_hash, condensat SHA-256 du certificat.

### Sortie

Objet de requête décodé.

**JSON**

```json
{ "typ": "oauth-authz-req+jwt", "alg": "ES256",
  "x5c": ["MIIC…(certificat d'accès du service)", "MIIC…(AC d'accès)"] }
{
  "client_id": "x509_hash:Uvo3HtuIxuhC92rShpgqcT3YXwrqRxWEviRiA0OZszk",
  "aud": "https://self-issued.me/v2",
  "response_type": "vp_token",
  "response_mode": "direct_post.jwt",
  "response_uri": "https://verifier.example.fr/post",
  "nonce": "n-0S6_WzA2Mj",
  "state": "eyJhb…6-sVA",
  "wallet_nonce": "qPmxiNFCR3QTm19POc8u",
  "dcql_query": {
    "credentials": [ {
      "id": "pid",
      "format": "dc+sd-jwt",
      "meta": { "vct_values": ["urn:eudi:pid:1"] },
      "claims": [
        { "path": ["family_name"] },
        { "path": ["given_name"] },
        { "path": ["birthdate"] }
      ]
    } ]
  },
  "client_metadata": {
    "jwks": { "keys": [ { "kty": "EC", "crv": "P-256", "x": "…", "y": "…",
                          "use": "enc", "alg": "ECDH-ES", "kid": "ac-1" } ] },
    "encrypted_response_enc_values_supported": ["A128GCM", "A256GCM"],
    "vp_formats_supported": { "dc+sd-jwt": { "sd-jwt_alg_values": ["ES256"],
                                             "kb-jwt_alg_values": ["ES256"] } }
  }
}
```

**NOTE.** wallet\_nonce n'est présent que parce que le portefeuille l'a fourni à l'étape 2 : l'objet signé est construit à la réception de cette requête POST.

**Suite :** La requête est déposée derrière une request\_uri : le portefeuille viendra la chercher.

## 3.2 Invoquer le portefeuille et récupérer la requête

Navigateur du service → Portefeuille · Invocation

### Entrée

Lien d'invocation puis requête du portefeuille.

**HTTP**

```http
haip-vp://?client_id=x509_hash%3AUvo3HtuIxuhC92rShpgqcT3YXwrqRxWEviRiA0OZszk
  &request_uri=https%3A%2F%2Fverifier.example.fr%2Frequest%2Fvapof4ql2i7m41m68uep
  &request_uri_method=post

POST /request/vapof4ql2i7m41m68uep HTTP/1.1
Host: verifier.example.fr
Content-Type: application/x-www-form-urlencoded
Accept: application/oauth-authz-req+jwt

wallet_metadata=%7B%22vp_formats_supported%22%3A…%7D&wallet_nonce=qPmxiNFCR3QTm19POc8u
```

### Traitement

1.  Le navigateur ouvre le portefeuille (schéma haip-vp://, lien https revendiqué, ou API Digital Credentials du navigateur).
2.  Le portefeuille envoie ses capacités et un nonce à lui, pour empêcher le rejeu d'une requête ancienne.

### Sortie

Réponse du service.

**HTTP**

```http
HTTP/1.1 200 OK
Content-Type: application/oauth-authz-req+jwt

eyJ0eXAiOiJvYXV0aC1hdXRoei1yZXErand0IiwiYWxnIjoiRVMyNTYiLCJ4NWMiOlsi…
```

**Suite :** Le portefeuille doit maintenant établir qui est ce service avant de montrer quoi que ce soit à l'utilisateur.

## 3.3 Vérifier l'identité du service

Portefeuille → Portefeuille · Contrôle du service

### Entrée

Objet de requête signé.

**TEXTE**

```text
En-tête x5c : [certificat d'accès, AC d'accès]
client_id    : x509_hash:Uvo3HtuIxuhC92rShpgqcT3YXwrqRxWEviRiA0OZszk
```

### Traitement

1.  Vérifier typ = oauth-authz-req+jwt, sinon rejet.
2.  Calculer BASE64URL(SHA-256(DER du certificat feuille)) et le comparer au client\_id après le préfixe.
3.  Vérifier la signature avec la clé du certificat feuille et la chaîne jusqu'à une ancre de la liste des fournisseurs de certificats d'accès.
4.  Vérifier que client\_id est identique dans l'URL et dans l'objet, et que wallet\_nonce est celui envoyé.

### Sortie

Écran de consentement (contenu).

**TEXTE**

```text
Service : <nom figurant dans le certificat d'accès>
Demande  : nom, prénom, date de naissance (issus de votre PID)
Non demandé : nationalité
```

**Suite :** L'utilisateur accepte et déverrouille la clé liée au PID.

## 3.4 Construire la présentation et la lier à la transaction

Portefeuille → WSCD · KB-JWT

### Entrée

Divulgations retenues et paramètres de la requête.

**TEXTE**

```text
JWT émetteur : eyJhbGciOiJFUzI1NiIsInR5cCI6ImRjK3NkLWp3dCIs…
Divulgations retenues : family_name, given_name, birthdate   (nationalities exclue)
aud = x509_hash:Uvo3HtuIxuhC92rShpgqcT3YXwrqRxWEviRiA0OZszk
nonce = n-0S6_WzA2Mj
```

### Traitement

1.  Assembler le SD-JWT présenté : JWT émetteur, puis les trois divulgations retenues, séparés par ~.
2.  Calculer sd\_hash = BASE64URL(SHA-256) de cette chaîne, tilde final compris.
3.  Faire signer par le WSCD le KB-JWT (Key Binding) avec la clé dont la publique figure dans cnf. aud et nonce rattachent la preuve à ce service et à cette transaction.

### Sortie

KB-JWT décodé et vp\_token.

**JSON**

```json
{ "typ": "kb+jwt", "alg": "ES256" }
{
  "iat": 1759482000,
  "aud": "x509_hash:Uvo3HtuIxuhC92rShpgqcT3YXwrqRxWEviRiA0OZszk",
  "nonce": "n-0S6_WzA2Mj",
  "sd_hash": "<BASE64URL(SHA-256(JWT~d1~d2~d3~))>"
}

vp_token = {
  "pid": [ "eyJhbGci…~WyIyR0xDNDJz…~WyJlbHVWNU9n…~WyI2SWo3dE0t…~eyJ0eXAiOiJrYitqd3QiLCJhbGci…" ]
}
```

**Suite :** La réponse est chiffrée pour le seul service avant d'être envoyée.

## 3.5 Envoyer la réponse chiffrée

Portefeuille → Service utilisateur · direct\_post.jwt

### Entrée

Contenu à chiffrer.

**JSON**

```json
{ "vp_token": { "pid": ["eyJhbGci…~…~eyJ0eXAiOiJrYitqd3Qi…"] }, "state": "eyJhb…6-sVA" }
```

### Traitement

1.  Accord ECDH-ES entre une clé éphémère du portefeuille et la clé ac-1 du service, sur P-256.
2.  Chiffrement A256GCM ; le résultat est un JWE compact, non signé (la signature est déjà dans le KB-JWT).
3.  Envoi en POST au response\_uri, paramètre response.

### Sortie

Requête et réponse.

**HTTP**

```http
// En-tête JWE
{ "alg": "ECDH-ES", "enc": "A256GCM", "kid": "ac-1",
  "epk": { "kty": "EC", "crv": "P-256", "x": "…", "y": "…" } }

POST /post HTTP/1.1
Host: verifier.example.fr
Content-Type: application/x-www-form-urlencoded

response=eyJhbGciOiJFQ0RILUVTIiwiZW5jIjoiQTI1NkdDTSIsImtpZCI6ImFjLTEi…

HTTP/1.1 200 OK
Content-Type: application/json
{ "redirect_uri": "https://verifier.example.fr/cb#response_code=091535f699ea575c7937fa5f0f454aee" }
```

**Suite :** Le service valide la présentation ; le portefeuille suit la redirection pour rattacher le résultat à la session d'origine.

## 3.6 Valider la présentation

Service utilisateur → Service utilisateur · Validation

### Entrée

JWE reçu.

**TEXTE**

```text
response = eyJhbGciOiJFQ0RILUVTIi…
```

### Traitement

1.  Déchiffrer avec la clé éphémère ac-1, puis vérifier state.
2.  JWT émetteur : vérifier ES256 avec la clé du certificat x5c et la chaîne jusqu'à la liste de confiance des fournisseurs de PID ; vérifier vct, exp.
3.  Divulgations : recalculer SHA-256 de chacune et vérifier sa présence dans \_sd.
4.  KB-JWT : vérifier la signature avec cnf.jwk, puis aud = client\_id du service, nonce = celui de la session, sd\_hash recalculé, iat récent.
5.  Statut : récupérer la liste de statut et lire le bit à l'index 41207.

### Sortie

Liste de statut (jeton décodé) et résultat.

**JSON**

```json
{ "typ": "statuslist+jwt", "alg": "ES256", "x5c": ["MIIC…"] }
{
  "sub": "https://pid.example.fr/statuslists/7",
  "iat": 1759478400,
  "exp": 1759564800,
  "ttl": 43200,
  "status_list": { "bits": 1, "lst": "eNrt3AENwCAMAEGWzbeCNb…" }
}
// lst : tableau de bits compressé (zlib). Bit à l'index 41207 : 0 = VALID, 1 = INVALID

Résultat : family_name = DUPONT, given_name = Camille, birthdate = 1990-04-12
Émetteur : fournisseur de PID inscrit sur la liste de confiance, attestation non révoquée
```

**Suite :** Le service ne libère le résultat qu'à la session qui présente le response\_code reçu par redirection.

## 3.7 Rattacher le résultat à la bonne session

Portefeuille → Navigateur du service · Redirection

### Entrée

Redirection suivie par le portefeuille.

**HTTP**

```http
GET /cb#response_code=091535f699ea575c7937fa5f0f454aee HTTP/1.1
Host: verifier.example.fr
```

### Traitement

1.  Le navigateur de l'utilisateur transmet le response\_code à l'interface du service.
2.  Le service vérifie que ce code correspond à la session qui a initié la demande ; sinon il rejette la présentation (exigence HAIP contre la fixation de session et le relais).

### Sortie

Résultat.

**TEXTE**

```text
Session authentifiée avec les trois attributs vérifiés
```

**Suite :** Le portefeuille journalise la transaction : date, service, données demandées et partagées (considérant 13 du règlement 2024/1183).

## Sources

-   [OpenID for Verifiable Presentations 1.0](https://openid.net/specs/openid-4-verifiable-presentations-1_0.html)
-   [OpenID4VC High Assurance Interoperability Profile 1.0](https://openid.net/specs/openid4vc-high-assurance-interoperability-profile-1_0.html)
-   [Règlement d'exécution (UE) 2024/2982 (protocoles et interfaces)](https://eur-lex.europa.eu/legal-content/EN/TXT/HTML/?uri=OJ%3AL_202402982)
-   [Règlement d'exécution (UE) 2026/1731, article 4 (certificats d'enregistrement : application au 11 août 2028)](https://eur-lex.europa.eu/eli/reg_impl/2026/1731/oj/fra)
-   [iGrant.io, synthèse du règlement 2026/1731](https://docs.igrant.io/regulations/implementing-acts-wallet-standards-update/)
-   [lawandtechnology.eu, calendrier des actes d'exécution](https://lawandtechnology.eu/en/european-digital-identity-wallet-december-2026-deadline-en/)
