---
url: 'https://www.corbado.com/it/blog/come-creare-verifier-credenziali-verificabili'
title: 'Come creare un Verifier di credenziali digitali (Guida per sviluppatori)'
description: 'Impara a creare da zero un verifier di credenziali digitali usando Next.js, OpenID4VP e ISO mDoc. Questa guida passo-passo per sviluppatori mostra come creare un verifier in grado di richiedere, ricevere e convalidare patenti di guida mobili e altre crede'
lang: 'it'
author: 'Amine'
date: '2025-08-20T15:39:23.520Z'
lastModified: '2026-03-27T07:06:20.937Z'
keywords: 'verifier credenziali digitali, tutorial verifier, creare verifier'
category: 'Digital Credentials'
---

# Come creare un Verifier di credenziali digitali (Guida per sviluppatori)

## 1. Introduzione

Dimostrare la propria identità online è una sfida costante, che porta a fare affidamento
sulle password e alla condivisione di documenti sensibili su canali non sicuri. Questo ha
reso la verifica dell'identità per le aziende un processo lento, costoso e soggetto a
frodi. Le [credenziali digitali](https://www.corbado.com/it/blog/digital-credentials-api) offrono un nuovo
approccio, ridando agli utenti il controllo dei propri dati. Sono l'equivalente digitale
di un [wallet](https://www.corbado.com/blog/digital-wallet-assurance) fisico, contenente di tutto, dalla patente
di guida alla laurea, ma con i vantaggi aggiuntivi di essere crittograficamente sicure,
rispettose della privacy e verificabili all'istante.

Questa guida offre agli sviluppatori un tutorial pratico e passo-passo per costruire un
verifier per le [credenziali digitali](https://www.corbado.com/it/blog/digital-credentials-api). Sebbene gli
standard esistano, ci sono poche indicazioni su come implementarli. Questo tutorial colma
questa lacuna, mostrando come costruire un verifier utilizzando l'API nativa per le
[credenziali digitali](https://www.corbado.com/it/blog/digital-credentials-api) del browser,
[OpenID4VP](https://www.corbado.com/glossary/open-id-4-vp) per il protocollo di presentazione e ISO
[mDoc](https://www.corbado.com/glossary/mdoc) (ad es., la
[patente di guida mobile](https://www.corbado.com/it/blog/patente-di-guida-mobile)) come formato della
credenziale.

Il risultato finale sarà un'applicazione [Next.js](https://www.corbado.com/blog/nextjs-passkeys) semplice ma
funzionale, in grado di richiedere, ricevere e verificare una credenziale digitale da un
[wallet](https://www.corbado.com/blog/digital-wallet-assurance) mobile compatibile.

Ecco una rapida anteprima dell'applicazione finale in azione. Il processo prevede quattro
passaggi principali:

**Passaggio 1: Pagina iniziale** L'utente arriva sulla pagina iniziale e clicca su
"Verifica con identità digitale" per avviare il processo.
![Pagina iniziale per la richiesta di verifica](https://s3.eu-central-1.amazonaws.com/corbado-cloud-staging-website-assets/Screenshot_2025_07_25_at_11_00_33_5217b35c96.png)

**Passaggio 2: Prompt di fiducia** Il browser chiede all'utente di dare fiducia. L'utente
clicca su "Continua" per procedere.
![Prompt di fiducia del browser](https://s3.eu-central-1.amazonaws.com/corbado-cloud-staging-website-assets/Screenshot_2025_07_25_at_11_00_39_ba390a8097.png)

**Passaggio 3: Scansione del codice QR** Viene visualizzato un
[codice QR](https://www.corbado.com/it/blog/codice-qr-login-autenticazione), che l'utente scansiona con la sua
applicazione [wallet](https://www.corbado.com/blog/digital-wallet-assurance) compatibile.
![Codice QR per la scansione](https://s3.eu-central-1.amazonaws.com/corbado-cloud-staging-website-assets/Screenshot_2025_07_25_at_11_00_45_3b30669a10.png)

**Passaggio 4: Credenziale decodificata** Dopo la verifica riuscita, l'applicazione mostra
i dati della credenziale decodificata.
![Risultato della credenziale decodificata](https://s3.eu-central-1.amazonaws.com/corbado-cloud-staging-website-assets/Screenshot_2025_07_25_at_11_01_36_684f7489cd.png)

### 1.1 Come funziona

La magia dietro le credenziali digitali risiede in un modello a "**triangolo della
fiducia**" semplice ma potente, che coinvolge tre attori chiave:

- **Issuer:** Un'autorità fidata (ad es., un'agenzia
  [governativa](https://www.corbado.com/passkeys-for-public-sector), un'università o una banca) che firma
  crittograficamente ed emette una credenziale a un utente.
- **Holder:** L'utente, che riceve la credenziale e la conserva in modo sicuro in un
  wallet digitale personale sul proprio dispositivo.
- **Verifier:** Un'applicazione o un servizio che deve controllare la credenziale
  dell'utente.

![Ecosistema delle credenziali verificabili W3C](https://www.w3.org/TR/vc-data-model/diagrams/ecosystem.svg)

Quando un utente vuole accedere a un servizio, presenta la credenziale dal suo wallet. Il
verifier può quindi verificarne istantaneamente l'autenticità senza dover contattare
direttamente l'[issuer](https://www.corbado.com/glossary/issuer) originale.

### 1.2 Perché i verifier sono essenziali (e perché sei qui)

Perché questo **ecosistema di identità decentralizzata** possa prosperare, il ruolo del
**verifier** è assolutamente cruciale. Sono i guardiani di questa nuova
[infrastruttura](https://www.corbado.com/passkeys-for-critical-infrastructure) di fiducia, coloro che consumano
le credenziali e le rendono utili nel mondo reale. Come illustra il diagramma sottostante,
un verifier completa il triangolo della fiducia richiedendo, ricevendo e convalidando una
credenziale dal holder.

Se sei uno sviluppatore, costruire un servizio per eseguire questa verifica è una
competenza fondamentale per la prossima generazione di applicazioni sicure e incentrate
sull'utente. Questa guida è progettata per accompagnarti esattamente in questo processo.
Tratteremo tutto ciò che devi sapere per **costruire il tuo verifier di credenziali
verificabili**, dai concetti e standard di base ai dettagli di implementazione passo-passo
per la convalida delle firme e il controllo dello stato delle credenziali.

> **Vuoi andare avanti?** Puoi trovare il progetto completo di questo tutorial su GitHub.
> Sentiti libero di clonarlo e provarlo tu stesso:
> [https://github.com/corbado/digital-credentials-example](https://github.com/corbado/digital-credentials-example)

Iniziamo.

## 2. Prerequisiti per costruire un Verifier

Prima di iniziare, assicurati di avere:

1. **Comprensione di base delle credenziali digitali e di mdoc**
    - Questo tutorial si concentra sul formato **ISO mDoc** (ad es., per le patenti di
      guida mobili) e non tratta altri formati come le
      [credenziali verificabili](https://www.corbado.com/it/glossary/open-id-4-vp) (VC) del W3C. Una certa
      familiarità con i concetti di base di [mdoc](https://www.corbado.com/glossary/mdoc) sarà utile.
2. **Docker e Docker Compose**
    - Il nostro progetto utilizza un database
      [MySQL](https://www.corbado.com/blog/passkey-webauthn-database-guide) in un container Docker per gestire lo
      stato della sessione OIDC. Assicurati di averli entrambi installati e in esecuzione.
3. **Protocollo scelto: OpenID4VP**
    - Useremo il protocollo **OpenID4VP** (OpenID for Verifiable Presentations) per il
      flusso di scambio delle credenziali.
4. **Stack tecnologico pronto**
    - Useremo **TypeScript** (Node.js) per la logica di backend.
    - Useremo **Next.js** sia per il backend (API routes) che per il frontend (UI).
    - Librerie chiave: librerie di decodifica [CBOR](https://www.corbado.com/glossary/cbor) per il parsing di
      [mdoc](https://www.corbado.com/glossary/mdoc) e un client [MySQL](https://www.corbado.com/blog/passkey-webauthn-database-guide).
5. **Credenziali di test e Wallet**
    - Useremo il
      **[CMWallet](https://github.com/digitalcredentialsdev/CMWallet/actions/runs/16407676816/artifacts/3574255220)**
      per [Android](https://www.corbado.com/blog/how-to-enable-passkeys-android), che comprende le richieste
      [OpenID4VP](https://www.corbado.com/glossary/open-id-4-vp) e può presentare credenziali mdoc.
6. **Conoscenze di base di crittografia**
    - Comprendere le firme digitali e i concetti di chiave pubblica/privata in relazione a
      mdoc e ai flussi OIDC.

---

Ora esamineremo in dettaglio ciascuno di questi prerequisiti, iniziando dagli standard e
protocolli che sono alla base di questo verifier basato su mdoc.

### 2.1 Scelte del protocollo

Il nostro verifier è costruito per quanto segue:

| Standard / Protocollo                                                                     | Descrizione                                                                                                                                                                                                       |
| :---------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **[W3C VC](https://www.w3.org/TR/vc-data-model/)**                                        | Il W3C Verifiable Credentials Data Model. Definisce la struttura standard per le credenziali digitali, inclusi claim, metadati e prove.                                                                           |
| **[SD-JWT](https://datatracker.ietf.org/doc/draft-ietf-oauth-selective-disclosure-jwt/)** | Selective Disclosure per JWT. Un formato per VC basato su JSON Web Token che consente ai titolari di divulgare selettivamente solo specifici claim da una credenziale, migliorando la privacy.                    |
| **[ISO mDoc](https://www.corbado.com/it/blog/digital-credentials-api)**                                          | ISO/IEC 18013-5. Lo standard internazionale per le patenti di guida mobili (mDL) e altri documenti d'identità mobili, che definisce le strutture dati e i protocolli di comunicazione per l'uso offline e online. |
| **OpenID4VP**                                                                             | OpenID for Verifiable Presentations. Un protocollo di presentazione interoperabile basato su OAuth 2.0. Definisce come un verifier richiede le credenziali e come il wallet di un holder le presenta.             |

Per questo tutorial, usiamo specificamente:

- **OpenID4VP** come protocollo per richiedere e ricevere le credenziali.
- **ISO mDoc** come formato della credenziale (ad es., per le patenti di guida mobili).

> **Nota sull'ambito:** Sebbene introduciamo brevemente W3C VC e SD-JWT per fornire un
> contesto più ampio, questo tutorial implementa esclusivamente credenziali
> [ISO mDoc](https://www.corbado.com/it/blog/digital-credentials-api) tramite
> [OpenID4VP](https://www.corbado.com/glossary/open-id-4-vp). Le VC basate su W3C sono fuori dall'ambito di
> questo esempio.

#### 2.1.1 ISO mDoc (Mobile Document)

Lo standard ISO/IEC 18013-5 mDoc definisce la struttura e la codifica per i documenti
mobili come le patenti di guida mobili (mDL). Le credenziali mDoc sono codificate in
[CBOR](https://www.corbado.com/glossary/cbor), firmate crittograficamente e possono essere presentate
digitalmente per la verifica. Il nostro verifier si concentrerà sulla decodifica e la
convalida di queste credenziali mdoc.

#### 2.1.2 OpenID4VP (OpenID for Verifiable Presentations)

OpenID4VP è un protocollo interoperabile per la richiesta e la presentazione di
credenziali digitali, basato su [OAuth 2.0](https://www.corbado.com/glossary/oauth2) e OpenID Connect. In questa
implementazione, OpenID4VP viene utilizzato per:

- Avviare il flusso di presentazione della credenziale (tramite
  [codice QR](https://www.corbado.com/it/blog/codice-qr-login-autenticazione) o API del browser)
- Ricevere la credenziale mdoc dal wallet dell'utente
- Garantire uno scambio di credenziali sicuro, stateful e rispettoso della privacy

### 2.2 Scelte dello stack tecnologico

Ora che abbiamo una chiara comprensione degli standard e dei protocolli, dobbiamo
scegliere lo stack tecnologico giusto per costruire il nostro verifier. Le nostre scelte
sono progettate per garantire robustezza, una buona esperienza per lo sviluppatore e
compatibilità con il moderno ecosistema web.

#### 2.2.1 Linguaggio: TypeScript

Useremo **TypeScript** sia per il nostro codice frontend che backend. Essendo un
soprainsieme di JavaScript, aggiunge la tipizzazione statica, che aiuta a individuare gli
errori precocemente, migliora la qualità del codice e rende più facili da gestire le
applicazioni complesse. In un contesto sensibile alla
[sicurezza](https://www.corbado.com/it/blog/come-abilitare-passkey-su-android) come la verifica delle
credenziali, la [sicurezza](https://www.corbado.com/it/blog/come-abilitare-passkey-su-android) dei tipi è un
enorme vantaggio.

#### 2.2.2 Framework: Next.js

**Next.js** è il nostro framework di scelta perché offre un'esperienza integrata e fluida
per la creazione di applicazioni full-stack.

- **Per il frontend:** Useremo [Next.js](https://www.corbado.com/blog/nextjs-passkeys) con
  [React](https://www.corbado.com/blog/react-passkeys) per costruire l'interfaccia utente in cui viene avviato il
  processo di verifica (ad es., visualizzando un
  [codice QR](https://www.corbado.com/it/blog/codice-qr-login-autenticazione)).
- **Per il backend:** Sfrutteremo le **API Routes di Next.js** per creare gli endpoint
  lato server. Questi endpoint sono responsabili della creazione di richieste OpenID4VP
  valide e di agire come `redirect_uri` per ricevere e verificare in modo sicuro la
  risposta finale dal CMWallet.

#### 2.2.3 Librerie chiave

La nostra implementazione si basa su un insieme specifico di librerie per il frontend e il
backend:

- **next**: Il framework [Next.js](https://www.corbado.com/blog/nextjs-passkeys), utilizzato sia per le API
  routes del backend che per l'interfaccia utente del frontend.
- **react** e **react-dom**: Alimentano l'interfaccia utente del frontend.
- **cbor-web**: Utilizzato per decodificare le credenziali mdoc codificate in
  [CBOR](https://www.corbado.com/glossary/cbor) in oggetti JavaScript utilizzabili.
- **mysql2**: Fornisce la connettività al database
  [MySQL](https://www.corbado.com/blog/passkey-webauthn-database-guide) per la memorizzazione delle challenge e
  delle sessioni di verifica.
- **uuid**: Una libreria per la generazione di stringhe di challenge (nonce) uniche.
- **@types/uuid**: Tipi TypeScript per la generazione di UUID.

> **Nota su `openid-client`:** Verifier più avanzati e di livello produttivo potrebbero
> utilizzare la libreria `openid-client` per gestire direttamente il protocollo OpenID4VP
> sul backend, abilitando funzionalità come un `redirect_uri` dinamico. In un flusso
> OpenID4VP guidato dal server con un `redirect_uri`, `openid-client` verrebbe utilizzato
> per analizzare e convalidare direttamente le risposte `vp_token`. Per questo tutorial,
> stiamo usando un flusso più semplice, mediato dal browser, che non lo richiede, rendendo
> il processo più facile da capire.

Questo stack tecnologico garantisce un'implementazione del verifier robusta, type-safe e
scalabile, focalizzata sull'API per le credenziali digitali del browser e sul formato
delle credenziali [ISO mDoc](https://www.corbado.com/it/blog/digital-credentials-api).

### 2.3 Ottenere un wallet e credenziali di test

Per testare il tuo verifier, hai bisogno di un wallet mobile in grado di interagire con
l'API per le credenziali digitali del browser.

Useremo il
**[CMWallet](https://github.com/digitalcredentialsdev/CMWallet/actions/runs/16407676816/artifacts/3574255220)**,
un robusto wallet di test compatibile con OpenID4VP per
[Android](https://www.corbado.com/blog/how-to-enable-passkeys-android).

**Come installare CMWallet (Android):**

1. **Scarica il file APK** utilizzando il link sopra direttamente sul tuo dispositivo
   [Android](https://www.corbado.com/blog/how-to-enable-passkeys-android).
2. Apri le **Impostazioni > Sicurezza** del tuo dispositivo.
3. Abilita **"Installa app sconosciute"** per il browser che hai utilizzato per scaricare
   il file.
4. Individua l'APK scaricato nella cartella "Download" e toccalo per avviare
   l'installazione.
5. Segui le istruzioni sullo schermo per completare l'installazione.
6. Apri CMWallet e lo troverai precaricato con credenziali di test, pronto per il flusso
   di verifica.

> **Nota:** Installa file APK solo da fonti di cui ti fidi. Il link fornito proviene dal
> repository ufficiale del progetto.

### 2.4 Conoscenze di crittografia

Prima di immergerci nell'implementazione, è essenziale comprendere i concetti
crittografici che sono alla base delle
[credenziali verificabili](https://www.corbado.com/it/glossary/open-id-4-vp). È questo che le rende
"verificabili" e affidabili.

#### 2.4.1 Firme digitali: il fondamento della fiducia

Nel suo nucleo, una credenziale verificabile è un insieme di attestazioni (come nome, data
di nascita, ecc.) che è stato firmato digitalmente da un [issuer](https://www.corbado.com/glossary/issuer). Una
firma digitale offre due garanzie cruciali:

- **Autenticità:** Dimostra che la credenziale è stata effettivamente creata
  dall'[issuer](https://www.corbado.com/glossary/issuer) e non da un impostore.
- **Integrità:** Dimostra che la credenziale non è stata alterata o manomessa da quando è
  stata firmata.

#### 2.4.2 Crittografia a chiave pubblica/privata

Le firme digitali vengono create utilizzando la crittografia a chiave pubblica/privata
(chiamata anche
[crittografia asimmetrica](https://www.corbado.com/it/blog/webauthn-pubkeycredparams-credentialpublickey)). Ecco
come funziona nel nostro contesto:

1. **L'Issuer ha una coppia di chiavi:** una chiave privata, che viene mantenuta segreta,
   e una chiave pubblica, che viene resa disponibile a tutti (solitamente tramite il loro
   DID Document).
2. **Firma:** Quando un issuer crea una credenziale, utilizza la sua **chiave privata**
   per generare una firma digitale unica per quei dati specifici della credenziale.
3. **Verifica:** Quando il nostro verifier riceve la credenziale, utilizza la **chiave
   pubblica** dell'issuer per controllare la firma. Se il controllo ha successo, il
   verifier sa che la credenziale è autentica e non è stata manomessa. Qualsiasi modifica
   ai dati della credenziale invaliderebbe la firma.

> **Nota sui DID:** In questo tutorial, non risolviamo le chiavi dell'issuer tramite DID.
> In produzione, gli issuer esporrebbero tipicamente le chiavi pubbliche tramite DID o
> altri endpoint autorevoli, che il verifier utilizzerebbe per la convalida crittografica.

#### 2.4.3 Credenziali verificabili come JWT

Le [credenziali verificabili](https://www.corbado.com/it/glossary/open-id-4-vp) sono spesso formattate come
**JSON Web Token (JWT)**. Un JWT è un modo compatto e sicuro per gli URL di rappresentare
le attestazioni da trasferire tra due parti. Un JWT firmato (noto anche come JWS) ha tre
parti separate da punti (`.`):

- **Header:** Contiene metadati sul token, come l'algoritmo di firma utilizzato (`alg`).
- **Payload:** Contiene le attestazioni effettive della credenziale verificabile (claim
  `vc`), inclusi `issuer`, `credentialSubject`, ecc.
- **Signature:** La firma digitale generata dall'issuer, che copre l'header e il payload.

```
// Esempio di una struttura JWT
[Header].[Payload].[Signature]
```

> **Nota:** Le credenziali verificabili basate su JWT sono fuori dall'ambito di questo
> post del blog. Questa implementazione si concentra sulle credenziali ISO mDoc e
> OpenID4VP, non sulle credenziali verificabili W3C o basate su JWT.

#### 2.4.4 La presentazione verificabile: provare il possesso

Non è sufficiente per un verifier sapere che una credenziale è valida; deve anche sapere
che la persona che _presenta_ la credenziale è il legittimo titolare. Questo impedisce a
qualcuno di usare una credenziale rubata.

Questo problema viene risolto utilizzando una **presentazione verificabile (VP)**. Una VP
è un involucro attorno a una o più VC che è **firmato dal titolare stesso**.

Il flusso è il seguente:

1. Il verifier chiede all'utente di presentare una credenziale.
2. Il wallet dell'utente crea una presentazione verificabile, raggruppa al suo interno le
   credenziali richieste e firma l'intera presentazione utilizzando la **chiave privata
   del titolare**.
3. Il wallet invia questa VP firmata al verifier.

Il nostro verifier deve quindi eseguire **due** controlli di firma separati:

1. **Verificare la/le credenziale/i:** Controllare la firma su ogni VC all'interno della
   presentazione utilizzando la **chiave pubblica dell'issuer**. (Dimostra che la
   credenziale è reale).
2. **Verificare la presentazione:** Controllare la firma sulla VP stessa utilizzando la
   **chiave pubblica del titolare**. (Dimostra che la persona che la presenta è il
   proprietario).

Questo controllo a due livelli garantisce sia l'autenticità della credenziale che
l'identità della persona che la presenta, creando un modello di fiducia robusto e sicuro.

> **Nota:** Il concetto di presentazioni verificabili come definito nell'ecosistema W3C VC
> è fuori dall'ambito di questo post del blog. Il termine presentazione verificabile qui
> si riferisce alla risposta OpenID4VP `vp_token`, che si comporta in modo simile a una VP
> W3C ma si basa sulla semantica ISO mDoc piuttosto che sul modello di firma
> [JSON-LD](https://www.corbado.com/glossary/json-ld) del W3C. Questa guida si concentra sulle credenziali ISO
> mDoc e OpenID4VP, non sulle presentazioni verificabili W3C o sulla loro validazione
> della firma.

## 3. Panoramica dell'architettura

La nostra architettura del verifier utilizza l'**API per le credenziali digitali**
integrata nel browser come intermediario sicuro per connettere la nostra applicazione web
con il **CMWallet** mobile dell'utente. Questo approccio semplifica il flusso lasciando
che sia il browser a gestire la visualizzazione nativa del codice QR e la comunicazione
con il wallet.

- **Frontend (Next.js & React):** Un sito web leggero rivolto all'utente. Il suo compito è
  recuperare un oggetto di richiesta dal nostro backend, passarlo all'API
  `navigator.credentials.get()` del browser, ricevere il risultato e inoltrarlo al nostro
  backend per la verifica.
- **Backend (API Routes di Next.js):** Il motore del verifier. Genera un oggetto di
  richiesta valido per l'API del browser ed espone un endpoint per ricevere la
  presentazione della credenziale dal frontend per la convalida finale.
- **Browser (API delle credenziali):** Il facilitatore. Riceve l'oggetto di richiesta dal
  nostro frontend, comprende il protocollo `openid4vp` e genera nativamente un codice QR.
  Attende quindi che il wallet restituisca una risposta.
- **CMWallet (App mobile):** Il wallet dell'utente. Scansiona il codice QR, elabora la
  richiesta, ottiene il consenso dell'utente e invia la risposta firmata al browser.

Ecco un diagramma di sequenza che illustra il flusso completo e accurato:

![Flusso di verifica tramite l'API per le credenziali digitali del browser](https://s3.eu-central-1.amazonaws.com/corbado-cloud-staging-website-assets/Mermaid_Chart_Create_complex_visual_diagrams_with_text_A_smarter_way_of_creating_diagrams_2025_07_24_233623_1b6ed9b957.svg)

**Spiegazione del flusso:**

1. **Avvio:** L'utente clicca sul pulsante "Verifica" sul nostro **frontend**.
2. **Oggetto di richiesta:** Il frontend chiama il nostro **backend**
   (`/api/verify/start`), che genera un oggetto di richiesta contenente la query e un
   nonce, quindi lo restituisce.
3. **Chiamata API del browser:** Il frontend chiama `navigator.credentials.get()` con
   l'oggetto di richiesta.
4. **Codice QR nativo:** Il **browser** vede la richiesta del protocollo `openid4vp` e
   visualizza nativamente un codice QR. La promessa `.get()` è ora in attesa.

> **Nota:** Questo flusso con codice QR avviene sui browser desktop. Sui browser mobili
> (Android Chrome con flag sperimentale abilitato), il browser può comunicare direttamente
> con i wallet compatibili sullo stesso dispositivo, eliminando la necessità di
> scansionare il codice QR. Per abilitare questa funzione su Android Chrome, vai su
> `chrome://flags#web-identity-digital-credentials` e imposta il flag su "Enabled".

5. **Scansione e presentazione:** L'utente scansiona il codice QR con **CMWallet**. Il
   wallet ottiene l'approvazione dell'utente e invia la presentazione verificabile al
   browser.
6. **Risoluzione della promessa:** Il browser riceve la risposta e la promessa `.get()`
   originale sul frontend si risolve finalmente, consegnando il payload della
   presentazione.
7. **Verifica del backend:** Il frontend invia il payload della presentazione tramite
   **POST** all'endpoint `/api/verify/finish` del nostro backend. Il backend convalida il
   nonce e la credenziale.
8. **Risultato:** Il backend restituisce un messaggio finale di successo o fallimento al
   frontend, che aggiorna l'interfaccia utente.

## 4. Costruire il Verifier

Ora che abbiamo una solida comprensione degli standard, dei protocolli e del flusso
architetturale, possiamo iniziare a costruire il nostro verifier.

> **Segui passo passo o usa il codice finale**
>
> Ora esamineremo la configurazione e l'implementazione del codice passo dopo passo. Se
> preferisci passare direttamente al prodotto finito, puoi clonare il progetto completo
> dal nostro repository GitHub ed eseguirlo localmente.
>
> ```bash
> git clone https://github.com/corbado/digital-credentials-example.git
> ```

### 4.1 Configurazione del progetto

Innanzitutto, inizializzeremo un nuovo progetto Next.js, installeremo le dipendenze
necessarie e avvieremo il nostro database.

#### 4.1.1 Inizializzazione dell'app Next.js

Apri il terminale, naviga nella directory in cui vuoi creare il tuo progetto ed esegui il
seguente comando. Per questo progetto stiamo usando l'App Router, TypeScript e Tailwind
CSS.

```bash
npx create-next-app@latest . --ts --eslint --tailwind --app --src-dir --import-alias "@/*" --use-npm
```

Questo comando crea lo scheletro di una nuova applicazione Next.js nella tua directory
corrente.

#### 4.1.2 Installazione delle dipendenze

Successivamente, dobbiamo installare le librerie che gestiranno la decodifica CBOR, le
connessioni al database e la generazione di UUID.

```bash
npm install cbor-web mysql2 uuid @types/uuid
```

Questo comando installa:

- `cbor-web`: Per la decodifica del payload della credenziale mdoc.
- `mysql2`: Il client MySQL per il nostro database.
- `uuid`: Per generare stringhe di challenge uniche.
- `@types/uuid`: Tipi TypeScript per la libreria `uuid`.

#### 4.1.3 Avvio del database

Il nostro backend richiede un database MySQL per memorizzare i dati della sessione OIDC,
garantendo che ogni flusso di verifica sia sicuro e stateful. Abbiamo incluso un file
`docker-compose.yml` per rendere questo processo semplice.

Se hai clonato il repository, puoi semplicemente eseguire `docker-compose up -d`. Se stai
costruendo da zero, crea un file chiamato `docker-compose.yml` con il seguente contenuto:

```yaml
services:
    mysql:
        image: mysql:8.0
        restart: always
        environment:
            MYSQL_ROOT_PASSWORD: rootpassword
            MYSQL_DATABASE: digital_credentials
            MYSQL_USER: app_user
            MYSQL_PASSWORD: app_password
        ports:
            - "3306:3306"
        volumes:
            - mysql_data:/var/lib/mysql
            - ./sql/init.sql:/docker-entrypoint-initdb.d/init.sql
        healthcheck:
            test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
            timeout: 20s
            retries: 10

volumes:
    mysql_data:
```

Questa configurazione di Docker Compose richiede anche uno script di inizializzazione SQL.
Crea una directory chiamata `sql` e al suo interno un file chiamato `init.sql` con il
seguente contenuto per configurare le tabelle necessarie:

```sql
-- Create database if not exists
CREATE DATABASE IF NOT EXISTS digital_credentials;
USE digital_credentials;

-- Table for storing challenges
CREATE TABLE IF NOT EXISTS challenges (
    id VARCHAR(36) PRIMARY KEY,
    challenge VARCHAR(255) NOT NULL UNIQUE,
    expires_at TIMESTAMP NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    used BOOLEAN DEFAULT FALSE,
    INDEX idx_challenge (challenge),
    INDEX idx_expires_at (expires_at)
);

-- Table for storing verification sessions
CREATE TABLE IF NOT EXISTS verification_sessions (
    id VARCHAR(36) PRIMARY KEY,
    challenge_id VARCHAR(36),
    status ENUM('pending', 'verified', 'failed', 'expired') DEFAULT 'pending',
    presentation_data JSON,
    verified_at TIMESTAMP NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (challenge_id) REFERENCES challenges(id) ON DELETE CASCADE,
    INDEX idx_challenge_id (challenge_id),
    INDEX idx_status (status)
);

-- Table for storing verified credentials data (optional)
CREATE TABLE IF NOT EXISTS verified_credentials (
    id VARCHAR(36) PRIMARY KEY,
    session_id VARCHAR(36),
    credential_type VARCHAR(255),
    issuer VARCHAR(255),
    subject VARCHAR(255),
    claims JSON,
    verified_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (session_id) REFERENCES verification_sessions(id) ON DELETE CASCADE,
    INDEX idx_session_id (session_id),
    INDEX idx_credential_type (credential_type)
);
```

Una volta che entrambi i file sono al loro posto, apri il terminale nella radice del
progetto ed esegui:

```bash
docker-compose up -d
```

Questo comando avvierà un container MySQL in background.

### 4.2 Panoramica dell'architettura dell'app Next.js

La nostra applicazione Next.js è strutturata per separare le responsabilità tra frontend e
backend, anche se fanno parte dello stesso progetto.

- **Frontend (`src/app/page.tsx`):** Una singola pagina [React](https://www.corbado.com/blog/react-passkeys) che
  avvia il flusso di verifica e visualizza il risultato. Interagisce con l'API per le
  credenziali digitali del browser.
- **Backend API Routes (`src/app/api/verify/...`):**
    - `start/route.ts`: Genera la richiesta OpenID4VP e un nonce di
      [sicurezza](https://www.corbado.com/it/blog/come-abilitare-passkey-su-android).
    - `finish/route.ts`: Riceve la presentazione dal wallet (tramite il browser),
      convalida il nonce e decodifica la credenziale.
- **Libreria (`src/lib/`):**
    - `database.ts`: Gestisce tutte le interazioni con il database (creazione di
      challenge, verifica delle sessioni).
    - `crypto.ts`: Gestisce la decodifica della credenziale mDoc basata su CBOR.

Ecco un diagramma che illustra l'architettura interna:

![Architettura interna di NextJS](https://s3.eu-central-1.amazonaws.com/corbado-cloud-staging-website-assets/Mermaid_Chart_Create_complex_visual_diagrams_with_text_A_smarter_way_of_creating_diagrams_2025_07_25_091202_f96ccb049f.svg)

### 4.3 Costruire il frontend

Il nostro frontend è intenzionalmente leggero. La sua responsabilità principale è agire
come trigger rivolto all'utente per il flusso di verifica e comunicare sia con il nostro
backend che con le capacità native di gestione delle credenziali del browser. Non contiene
alcuna logica di protocollo complessa; tutto ciò è delegato.

Nello specifico, il frontend gestirà quanto segue:

- **Interazione con l'utente:** Fornisce un'interfaccia semplice, come un pulsante
  "Verifica", per consentire all'utente di avviare il processo.
- **Gestione dello stato:** Gestisce lo stato dell'interfaccia utente, mostrando
  indicatori di caricamento mentre la verifica è in corso e visualizzando il messaggio
  finale di successo o errore.
- **Comunicazione con il backend (richiesta):** Chiama `/api/verify/start` e riceve un
  payload JSON strutturato (`protocol`, `request`, `state`) che descrive esattamente cosa
  il wallet dovrebbe presentare.
- **Invocazione dell'API del browser:** Passa quell'oggetto JSON a
  `navigator.credentials.get()`, che renderizza un codice QR nativo e attende la risposta
  del wallet.
- **Comunicazione con il backend (risposta):** Una volta che l'API del browser restituisce
  la presentazione verificabile, invia questi dati al nostro endpoint `/api/verify/finish`
  in una richiesta POST per la convalida finale lato server.
- **Visualizzazione dei risultati:** Aggiorna l'interfaccia utente per informare l'utente
  se la verifica è andata a buon fine o è fallita, in base alla risposta del backend.

La logica principale si trova nella funzione `startVerification`:

```typescript
// src/app/page.tsx

const startVerification = async () => {
    setLoading(true);
    setVerificationResult(null);

    try {
        // 1. Controlla se il browser supporta l'API
        if (!navigator.credentials?.get) {
            throw new Error("Il browser non supporta la Credential API.");
        }

        // 2. Chiedi al nostro backend un oggetto di richiesta
        const res = await fetch("/api/verify/start");
        const { protocol, request } = await res.json();

        // 3. Passa quell'oggetto al browser – questo attiva il codice QR nativo
        const credential = await (navigator.credentials as any).get({
            mediation: "required",
            digital: {
                requests: [
                    {
                        protocol, // "openid4vp"
                        data: request, // contiene dcql_query, nonce, ecc.
                    },
                ],
            },
        });

        // 4. Inoltra la risposta del wallet (dal browser) al nostro endpoint di fine per i controlli lato server
        const verifyRes = await fetch("/api/verify/finish", {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify(credential),
        });

        const result = await verifyRes.json();

        if (verifyRes.ok && result.verified) {
            setVerificationResult(`Successo: ${result.message}`);
        } else {
            throw new Error(result.message || "Verifica fallita.");
        }
    } catch (err) {
        setVerificationResult(`Errore: ${(err as Error).message}`);
    } finally {
        setLoading(false);
    }
};
```

Questa funzione mostra i quattro passaggi chiave della logica del frontend: controllo del
supporto API, recupero della richiesta dal backend, chiamata all'API del browser e invio
del risultato per la verifica. Il resto del file è boilerplate
[React](https://www.corbado.com/blog/react-passkeys) standard per la gestione dello stato e il rendering
dell'interfaccia utente, che puoi visualizzare nel
[repository GitHub](https://github.com/corbado/digital-credentials-example).

#### Perché `digital` e `mediation: 'required'`?

Potresti notare che la nostra chiamata a `navigator.credentials.get()` sembra diversa da
esempi più semplici. Questo perché stiamo aderendo rigorosamente alla
[specifica ufficiale dell'API per le credenziali digitali del W3C](https://www.w3.org/TR/digital-credentials/#the-digital-credentials-api).

- **Membro `digital`:** La specifica richiede che tutte le richieste di credenziali
  digitali siano annidate all'interno di un oggetto `digital`. Questo fornisce uno spazio
  dei nomi chiaro e standardizzato per questa API, distinguendola da altri tipi di
  credenziali (come `password` o `federated`) e consentendo estensioni future senza
  conflitti.

- **`mediation: 'required'`:** Questa opzione è una caratteristica cruciale per la
  sicurezza e l'esperienza dell'utente. Impone che l'utente debba interagire attivamente
  con un prompt (ad es., una scansione biometrica, l'inserimento di un PIN o una schermata
  di consenso) per approvare la richiesta di credenziali. Senza di essa, un sito web
  potrebbe potenzialmente tentare di accedere silenziosamente alle credenziali in
  background, il che rappresenta un rischio significativo per la privacy. Richiedendo la
  mediazione, garantiamo che l'utente sia sempre in controllo e dia il consenso esplicito
  per ogni transazione.

### 4.4 Costruire gli endpoint del backend

Con l'interfaccia utente React pronta, ora abbiamo bisogno di due API routes che svolgano
il lavoro pesante sul server:

1. **`/api/verify/start`** – costruisce una richiesta OpenID4VP, salva una challenge
   monouso in MySQL e restituisce tutto al browser.
2. **`/api/verify/finish`** – riceve la risposta del wallet, convalida la challenge,
   verifica e decodifica la credenziale e infine restituisce un risultato JSON conciso
   all'interfaccia utente.

#### 4.4.1 `/api/verify/start`: Generare la richiesta OpenID4VP

```typescript
// src/app/api/verify/start/route.ts
import { NextResponse } from "next/server";
import { v4 as uuidv4 } from "uuid";
import { createChallenge, cleanupExpiredChallenges } from "@/lib/database";

export async function GET() {
    // 1️⃣  Crea un nonce (challenge) casuale e di breve durata
    const challenge = uuidv4();
    const challengeId = uuidv4();
    const expiresAt = new Date(Date.now() + 5 * 60 * 1000);

    await createChallenge(challengeId, challenge, expiresAt);
    cleanupExpiredChallenges().catch(console.error);

    // 2️⃣  Costruisci una query DCQL che descrive *cosa* vogliamo
    const dcqlQuery = {
        credentials: [
            {
                id: "cred1",
                format: "mso_mdoc",
                meta: { doctype_value: "eu.europa.ec.eudi.pid.1" },
                claims: [
                    { path: ["eu.europa.ec.eudi.pid.1", "family_name"] },
                    { path: ["eu.europa.ec.eudi.pid.1", "given_name"] },
                    { path: ["eu.europa.ec.eudi.pid.1", "birth_date"] },
                ],
            },
        ],
    };

    // 3️⃣  Restituisci un oggetto che il browser può passare a navigator.credentials.get()
    return NextResponse.json({
        protocol: "openid4vp", // dice al browser quale protocollo di wallet usare
        request: {
            dcql_query: dcqlQuery, // COSA presentare
            nonce: challenge, // anti-replay
            response_type: "vp_token",
            response_mode: "dc_api", // il wallet farà una POST direttamente a /finish
        },
        state: {
            credential_type: "mso_mdoc", // conservato per controlli successivi
            nonce: challenge,
            challenge_id: challengeId,
        },
    });
}
```

> **Parametri chiave**
>
> • **`nonce`** – sfida crittografica che lega richiesta e risposta (previene il replay).
> • **`dcql_query`** – Un oggetto che descrive le attestazioni esatte di cui abbiamo
> bisogno. Per questa guida, usiamo una struttura `dcql_query` ispirata alle recenti bozze
> del Digital Credential Query Language, anche se non è ancora uno standard finalizzato. •
> **`state`** – JSON arbitrario restituito dal wallet in modo che possiamo cercare il
> record nel database.

#### 4.4.2 Helper del database

Il file `src/lib/database.ts` racchiude le operazioni MySQL di base per le challenge e le
sessioni di verifica (inserimento, lettura, contrassegno come usato). Mantenere questa
logica in un unico modulo rende facile sostituire il datastore in seguito.

---

### 4.5 `/api/verify/finish`: Convalidare e decodificare la presentazione

```typescript
// src/app/api/verify/finish/route.ts
import { NextResponse, NextRequest } from "next/server";
import { v4 as uuidv4 } from "uuid";
import {
    getChallenge,
    markChallengeAsUsed,
    createVerificationSession,
    updateVerificationSession,
} from "@/lib/database";
import { decodeDigitalCredential, decodeAllNamespaces } from "@/lib/crypto";

export async function POST(request: NextRequest) {
    const body = await request.json();

    // 1️⃣  Estrai i pezzi della presentazione verificabile
    const vpTokenMap = body.vp_token ?? body.data?.vp_token;
    const state = body.state;
    const mdocToken = vpTokenMap?.cred1; // abbiamo richiesto questo ID in dcqlQuery

    if (!vpTokenMap || !state || !mdocToken) {
        return NextResponse.json(
            { verified: false, message: "Risposta malformata" },
            { status: 400 },
        );
    }

    // 2️⃣  Validazione della challenge monouso
    const stored = await getChallenge(state.nonce);
    if (!stored) {
        return NextResponse.json(
            { verified: false, message: "Challenge non valida o scaduta" },
            { status: 400 },
        );
    }

    const sessionId = uuidv4();
    await createVerificationSession(sessionId, stored.id);

    // 3️⃣  Controlli crittografici (pseudo) – sostituire con una vera validazione mDL in produzione
    // In un'applicazione reale, useresti una libreria dedicata per eseguire una validazione crittografica completa
    // della firma mdoc rispetto alla chiave pubblica dell'issuer.
    const isValid = mdocToken.length > 0;
    if (!isValid) {
        await updateVerificationSession(sessionId, "failed", {
            reason: "validazione mdoc fallita",
        });
        return NextResponse.json(
            { verified: false, message: "Validazione della credenziale fallita" },
            { status: 400 },
        );
    }

    // 4️⃣  Decodifica il payload del mobile-DL (mdoc) in JSON leggibile
    const decoded = await decodeDigitalCredential(mdocToken);
    const readable = decodeAllNamespaces(decoded)["eu.europa.ec.eudi.pid.1"];

    await markChallengeAsUsed(state.nonce);
    await updateVerificationSession(sessionId, "verified", { readable });

    return NextResponse.json({
        verified: true,
        message: "Credenziale mdoc verificata con successo!",
        credentialData: readable,
        sessionId,
    });
}
```

> **Campi importanti nella risposta del wallet**
>
> • **`vp_token`** – mappa che contiene _ciascuna_ credenziale restituita dal wallet. Per
> la nostra demo prendiamo `vp_token.cred1`. • **`state`** – eco del blob che abbiamo
> fornito in `/start`; contiene il `nonce` in modo da poter cercare il record nel
> database. • **`mdocToken`** – una struttura CBOR codificata in Base64URL che rappresenta
> l'ISO mDoc.

### 4.6 Decodifica della credenziale mdoc

Quando il verifier riceve una credenziale mdoc dal browser, si tratta di una stringa
Base64URL contenente dati binari codificati in CBOR. Per estrarre le attestazioni
effettive, l'endpoint `finish` esegue un processo di decodifica a più passaggi utilizzando
funzioni di supporto da `src/lib/crypto.ts`.

#### 4.6.1 Passaggio 1: Decodifica Base64URL e CBOR

La funzione `decodeDigitalCredential` gestisce la conversione dalla stringa codificata a
un oggetto utilizzabile:

```typescript
// src/lib/crypto.ts
export async function decodeDigitalCredential(encodedCredential: string) {
    // 1. Converti Base64URL in Base64 standard
    const base64UrlToBase64 = (input: string) => {
        let base64 = input.replace(/-/g, "+").replace(/_/g, "/");
        const pad = base64.length % 4;
        if (pad) base64 += "=".repeat(4 - pad);
        return base64;
    };

    const base64 = base64UrlToBase64(encodedCredential);

    // 2. Decodifica Base64 in binario
    const binaryString = atob(base64);
    const byteArray = Uint8Array.from(binaryString, (char) => char.charCodeAt(0));

    // 3. Decodifica CBOR
    const decoded = await cbor.decodeFirst(byteArray);
    return decoded;
}
```

- **Da Base64URL a Base64:** Converte la credenziale da Base64URL a codifica Base64
  standard.
- **Da Base64 a binario:** Decodifica la stringa Base64 in un array di byte binario.
- **Decodifica CBOR:** Utilizza la libreria `cbor-web` per decodificare i dati binari in
  un oggetto JavaScript strutturato.

#### 4.6.2 Passaggio 2: Estrazione delle attestazioni con namespace

La funzione `decodeAllNamespaces` elabora ulteriormente l'oggetto CBOR decodificato per
estrarre le attestazioni effettive dai namespace pertinenti:

```typescript
// src/lib/crypto.ts
export function decodeAllNamespaces(jsonObj) {
    const decoded = {};

    try {
        jsonObj.documents.forEach((doc, idx) => {
            // 1) issuerSigned.nameSpaces:
            const issuerNS = doc.issuerSigned?.nameSpaces || {};
            Object.entries(issuerNS).forEach(([nsName, entries]) => {
                if (!decoded[nsName]) decoded[nsName] = {};
                (entries as any[]).forEach((entry) => {
                    const bytes = Uint8Array.from(entry.value);
                    const decodedEntry = cbor.decodeFirstSync(bytes);
                    Object.assign(decoded[nsName], decodedEntry);
                });
            });

            // 2) deviceSigned.nameSpaces (se presente):
            const deviceNS = doc.deviceSigned?.nameSpaces;
            if (deviceNS?.value?.data) {
                const bytes = Uint8Array.from(deviceNS.value);
                decoded[`deviceSigned_ns_${idx}`] = cbor.decodeFirstSync(bytes);
            }
        });
    } catch (e) {
        console.error(e);
    }

    return decoded;
}
```

- **Itera su tutti i documenti** nella credenziale decodificata.
- **Decodifica ogni namespace** (ad es., `eu.europa.ec.eudi.pid.1`) per estrarre i valori
  effettivi delle attestazioni (come nome, data di nascita, ecc.).
- **Gestisce sia i namespace firmati dall'issuer che quelli firmati dal dispositivo**, se
  presenti.

#### Esempio di output

Dopo aver eseguito questi passaggi, l'endpoint finish ottiene un oggetto leggibile
dall'uomo contenente le attestazioni dal mdoc, ad esempio:

```json
{
    "family_name": "Doe",
    "given_name": "John",
    "birth_date": "1990-01-01"
}
```

Questo processo garantisce che il verifier possa estrarre in modo sicuro e affidabile le
informazioni necessarie dalla credenziale mdoc per la visualizzazione e l'ulteriore
elaborazione.

### 4.7 Visualizzazione del risultato nell'interfaccia utente

L'endpoint finish restituisce un oggetto JSON minimo al frontend:

```json
{
    "verified": true,
    "message": "Credenziale mdoc verificata con successo!",
    "credentialData": {
        "family_name": "Doe",
        "given_name": "John",
        "birth_date": "1990-01-01"
    }
}
```

Il frontend riceve questa risposta in `startVerification()` e la salva semplicemente nello
stato di React in modo da poter renderizzare una bella scheda di conferma o visualizzare
singole attestazioni – ad es. _“Benvenuto, John Doe (nato il 1990-01-01)!”_.

## 5. Eseguire il Verifier e passi successivi

Ora hai un verifier completo e funzionante che utilizza le capacità native di gestione
delle credenziali del browser. Ecco come eseguirlo localmente e cosa puoi fare per
portarlo da una proof-of-concept a un'applicazione pronta per la produzione.

### 5.1 Come eseguire l'esempio

1. **Clona il repository:**

    ```bash
    git clone https://github.com/corbado/digital-credentials-example.git
    cd digital-credentials-example
    ```

2. **Installa le dipendenze:**

    ```bash
    npm install
    ```

3. **Avvia il database:** Assicurati che Docker sia in esecuzione sulla tua macchina,
   quindi avvia il container MySQL:

    ```bash
    docker-compose up -d
    ```

4. **Esegui l'applicazione:**

    ```bash
    npm run dev
    ```

    Apri il browser all'indirizzo `http://localhost:3000` e dovresti vedere l'interfaccia
    utente del verifier. Ora puoi usare il tuo CMWallet per scansionare il codice QR e
    completare il flusso di verifica.

### 5.2 Passi successivi: dalla demo alla produzione

Questo tutorial fornisce i mattoni fondamentali per un verifier. Per renderlo pronto per
la produzione, dovresti implementare diverse funzionalità aggiuntive:

- **Validazione crittografica completa:** L'implementazione attuale utilizza un controllo
  segnaposto (`mdocToken.length > 0`). In uno scenario reale, è necessario eseguire una
  validazione crittografica completa della firma mdoc rispetto alla chiave pubblica
  dell'issuer (ad es., risolvendo il loro DID o recuperando il loro certificato di chiave
  pubblica). Per gli standard di risoluzione dei DID, fare riferimento alla
  [specifica W3C DID Resolution](https://www.w3.org/TR/did-resolution/).

- **Controllo della revoca dell'issuer:** Le credenziali possono essere revocate
  dall'issuer prima della loro data di scadenza. Un verifier di produzione deve
  controllare lo stato della credenziale interrogando una lista di revoca o un endpoint di
  stato fornito dall'issuer. La
  [W3C Verifiable Credentials Status List](https://www.w3.org/TR/vc-bitstring-status-list/)
  fornisce lo standard per le liste di revoca delle credenziali.

- **Gestione robusta degli errori e sicurezza:** Aggiungi una gestione completa degli
  errori, la validazione degli input, il rate-limiting sugli endpoint API e assicurati che
  tutte le comunicazioni avvengano tramite HTTPS (TLS) per proteggere i dati in transito.
  Le [OWASP API Security Guidelines](https://owasp.org/www-project-api-security/)
  forniscono best practice complete per la sicurezza delle API.

- **Supporto per più tipi di credenziali:** Estendi la logica per gestire diversi valori
  di `doctype` e formati di credenziali se prevedi di ricevere più della sola credenziale
  PID dell'identità digitale europea (EUDI). Il
  [W3C Verifiable Credentials Data Model](https://www.w3.org/TR/vc-data-model/) fornisce
  specifiche complete sul formato delle VC.

### 5.3 Cosa è fuori dall'ambito di questo tutorial

Questo esempio è volutamente incentrato sul flusso principale mediato dal browser per
renderlo facile da capire. I seguenti argomenti sono considerati fuori dall'ambito:

- **Sicurezza pronta per la produzione:** Il verifier è a scopo educativo e manca del
  rafforzamento necessario per un ambiente live.
- **Credenziali verificabili W3C:** Questo tutorial si concentra esclusivamente sul
  formato ISO mDoc per le patenti di guida mobili. Non copre altri formati popolari come
  JWT-VC o VC con Linked Data Proofs (LD-Proofs).
- **Flussi OpenID4VP avanzati:** Non implementiamo funzionalità OpenID4VP più complesse,
  come la comunicazione diretta wallet-backend tramite un `redirect_uri` o la
  registrazione dinamica del client.

Basandoti su queste fondamenta e incorporando questi passaggi successivi, puoi sviluppare
un verifier robusto e sicuro in grado di fidarsi e convalidare le credenziali digitali
nelle tue applicazioni.

## Conclusione

Ecco fatto! Con meno di 250 righe di TypeScript, ora abbiamo un verifier end-to-end che:

1. Pubblica una richiesta per l'API delle credenziali del browser.
2. Permette a qualsiasi wallet compatibile di fornire una presentazione verificabile.
3. Convalida la presentazione sul server.
4. Aggiorna l'interfaccia utente in tempo reale.

In produzione, sostituiresti la validazione segnaposto con controlli completi
[ISO 18013-5](https://www.corbado.com/glossary/iso-18013-5), aggiungeresti controlli di revoca dell'issuer,
rate-limiting, audit logging e, naturalmente, TLS end-to-end, ma i mattoni fondamentali
rimangono esattamente gli stessi.

## Risorse

Ecco alcune delle risorse chiave, specifiche e strumenti utilizzati o citati in questo
tutorial:

- **Repository del progetto:**
    - [Codice sorgente completo su GitHub](https://github.com/corbado/digital-credentials-example)

- **Specifiche chiave:**
    - [W3C Verifiable Credentials Data Model](https://www.w3.org/TR/vc-data-model/): Lo
      standard fondamentale per le VC.
    - [OpenID for Verifiable Presentations (OpenID4VP)](https://openid.net/specs/openid-4-verifiable-presentations-1_0.html):
      Il protocollo di presentazione utilizzato per lo scambio di credenziali.
    - [ISO/IEC 18013-5 (mDoc)](https://www.iso.org/standard/69084.html): Lo standard
      internazionale per le patenti di guida mobili (mDL).
    - [W3C Digital Credentials API](https://www.w3.org/TR/digital-credentials/#the-digital-credentials-api):
      L'API del browser utilizzata per richiedere credenziali da un wallet.

- **Strumenti:**
    - [CMWallet per Android](https://github.com/digitalcredentialsdev/CMWallet/actions/runs/16407676816/artifacts/3574255220):
      Il wallet di test utilizzato in questa guida.

- **Librerie:**
    - Next.js: Il framework React per costruire il frontend e il backend.
    - [cbor-web](https://github.com/hildjj/cbor-web): Per la decodifica di credenziali
      mdoc codificate in CBOR.
    - [mysql2](https://github.com/sidorares/node-mysql2): Il client MySQL per
      [Node.js](https://www.corbado.com/blog/nodejs-passkeys).
