---
title: Verificare la credenziale di un passaporto
description: "Scaricate la credenziale W3C firmata di un passaporto, risolvete la chiave did:web e verificate la firma ES256 da soli, con curl, Node o Python."
canonical: "https://www.tracepass.eu/it/docs/verify-credentials"
locale: it
source: "https://www.tracepass.eu/it/docs/verify-credentials"
---

# Verificare la credenziale di un passaporto

> Scaricate la credenziale W3C firmata di un passaporto, risolvete la chiave did:web e verificate la firma ES256 da soli, con curl, Node o Python.

Ogni versione di un passaporto TracePass pubblicato è emessa come verifiable credential W3C firmata nel formato del passaporto digitale di prodotto UNTP 0.7.0\. Potete verificare che i dati di un passaporto provengono da TracePass e non sono stati modificati, senza account e senza chiederci nulla. Questa pagina lo mostra sul passaporto demo pubblico.

## 1\. Scaricate la credenziale

```bash
curl --http2 -H "Accept: application/vc+jwt" \
  https://id.tracepass.eu/01/99999999999997/21/6B27A0000001 \
  -o credential.jwt
```

L'URL stesso del passaporto restituisce la credenziale quando chiedete `application/vc+jwt`. Gli URL dei passaporti richiedono HTTP/2 (EN 18216), quindi gli strumenti che parlano solo HTTP/1.1 ricevono 505\. L'header `Link` della risposta, il linkset del passaporto e l'intestazione della pagina HTML segnalano la credenziale. Un passaporto senza una versione corrente firmata risponde 406, e un passaporto sospeso, scaduto o archiviato non ne serve nessuna.

## 2\. Leggete l'intestazione

La credenziale è un JWS compatto. La sua intestazione protetta indica come è stata firmata:

```json
{
  "alg": "ES256",
  "typ": "vc+jwt",
  "cty": "vc",
  "kid": "did:web:www.tracepass.eu#key-1"
}
```

Il payload è la credenziale stessa (VC-JOSE-COSE), non un claim `vc` di VC 1.1\. `kid` indica l'emittente e la chiave con cui è stata firmata.

## 3\. Risolvete la chiave dell'emittente

L'emittente è `did:web:www.tracepass.eu`. Un identificatore did:web si risolve in un documento su quel dominio, qui `https://www.tracepass.eu/.well-known/did.json`, che pubblica la chiave pubblica con il `kid` dell'intestazione. La firma lega la credenziale al controllo del dominio.

## 4\. Verificate la firma

Entrambi gli esempi recuperano la chiave e verificano la firma ES256:

```javascript
// npm install jose
import { readFileSync } from "node:fs";
import { decodeProtectedHeader, importJWK, jwtVerify } from "jose";

const jws = readFileSync("credential.jwt", "utf8").trim();
const { kid } = decodeProtectedHeader(jws); // did:web:www.tracepass.eu#key-1
const did = kid.split("#")[0];
// did:web:<host> resolves to https://<host>/.well-known/did.json
const doc = await (await fetch(`https://${did.slice("did:web:".length)}/.well-known/did.json`)).json();
const method = doc.verificationMethod.find((m) => m.id === kid);
const { payload } = await jwtVerify(jws, await importJWK(method.publicKeyJwk, "ES256"), { typ: "vc+jwt" });
console.log("Verified. Issuer:", payload.issuer.id, "Product:", payload.credentialSubject.id);
```

```python
# pip install "pyjwt[crypto]" requests
import jwt, requests

token = open("credential.jwt").read().strip()
kid = jwt.get_unverified_header(token)["kid"]  # did:web:www.tracepass.eu#key-1
did = kid.split("#")[0]
# did:web:<host> resolves to https://<host>/.well-known/did.json
doc = requests.get(f"https://{did.removeprefix('did:web:')}/.well-known/did.json").json()
jwk = next(m["publicKeyJwk"] for m in doc["verificationMethod"] if m["id"] == kid)
claims = jwt.decode(token, jwt.PyJWK(jwk).key, algorithms=["ES256"])
print("Verified. Issuer:", claims["issuer"]["id"], "Product:", claims["credentialSubject"]["id"])
```

Una credenziale modificata dopo la firma, anche di un solo carattere, fallisce con un errore di firma.

## 5\. Controllate il formato (facoltativo)

Per confermare che la credenziale segue UNTP 0.7.0, validatela rispetto allo schema ufficiale UNTP:

```python
# pip install jsonschema requests "pyjwt[crypto]"
import jwt, requests
from jsonschema import Draft202012Validator

token = open("credential.jwt").read().strip()
credential = jwt.decode(token, options={"verify_signature": False})  # verify first, as above
for claim in ("iss", "sub", "iat"):
    credential.pop(claim, None)  # JWT claims, not part of the credential
schema = requests.get("https://untp.unece.org/artefacts/schema/v0.7.0/dpp/DigitalProductPassport.json").json()
errors = [e.message for e in Draft202012Validator(schema).iter_errors(credential)]
print("UNTP 0.7.0 schema errors:", errors or "none")
```

UNTP richiede inoltre l'identificativo dello stabilimento di produzione e il paese di produzione. La credenziale li contiene quando il passaporto li registra e altrimenti li omette, quindi è pienamente valida rispetto allo schema UNTP solo per quei passaporti. Il passaporto demo si valida senza errori.

## Che cosa dimostra una firma valida

Che TracePass ha emesso esattamente questi dati per questa versione del passaporto e che nessuno li ha modificati da allora. È una firma did:web: dimostra il controllo di tracepass.eu, con la stessa forza di HTTPS. Non è un sigillo elettronico qualificato eIDAS.

Copre solo la vista pubblica del passaporto, mai i campi ad accesso riservato o per le autorità, quindi non è il registro legale completo. Non esiste ancora una lista di revoca: una copia già in possesso di qualcuno continua a risultare valida anche dopo la sospensione del passaporto, quindi verificate lo stato attuale nel passaporto pubblicato.

Provate sul passaporto demo, <https://id.tracepass.eu/01/99999999999997/21/6B27A0000001>, o su qualsiasi passaporto pubblicato di cui avete l'URL.
