---
title: Pass-Credential prüfen
description: "Laden Sie das signierte W3C-Credential eines Passes, lösen Sie den did:web-Schlüssel auf und prüfen Sie die ES256-Signatur mit curl, Node oder Python."
canonical: "https://www.tracepass.eu/de/docs/verify-credentials"
locale: de
source: "https://www.tracepass.eu/de/docs/verify-credentials"
---

# Pass-Credential prüfen

> Laden Sie das signierte W3C-Credential eines Passes, lösen Sie den did:web-Schlüssel auf und prüfen Sie die ES256-Signatur mit curl, Node oder Python.

Jede Version eines veröffentlichten TracePass-Passes wird als signiertes W3C-verifiable credential im Format des digitalen Produktpasses UNTP 0.7.0 ausgestellt. Sie können prüfen, dass die Daten eines Passes von TracePass stammen und nicht verändert wurden, ohne Konto und ohne uns zu fragen. Diese Seite zeigt es am öffentlichen Demo-Pass.

## 1\. Credential abrufen

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

Die Pass-URL selbst liefert das Credential, wenn Sie `application/vc+jwt` anfordern. Pass-URLs verlangen HTTP/2 (EN 18216), Werkzeuge, die nur HTTP/1.1 sprechen, erhalten daher 505\. Der `Link`\-Header der Antwort, das Linkset des Passes und der Kopf der HTML-Seite weisen auf das Credential hin. Ein Pass ohne signierte aktuelle Version antwortet mit 406, ein ausgesetzter, abgelaufener oder archivierter Pass liefert keins.

## 2\. Header lesen

Das Credential ist ein kompakter JWS. Sein geschützter Header zeigt, wie es signiert wurde:

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

Die Nutzlast ist das Credential selbst (VC-JOSE-COSE), kein `vc`\-Claim aus VC 1.1\. `kid` nennt den Aussteller und den Schlüssel, mit dem signiert wurde.

## 3\. Schlüssel des Ausstellers auflösen

Aussteller ist `did:web:www.tracepass.eu`. Ein did:web-Identifikator wird zu einem Dokument auf dieser Domain aufgelöst, hier `https://www.tracepass.eu/.well-known/did.json`, das den öffentlichen Schlüssel unter dem `kid` aus dem Header veröffentlicht. Die Signatur bindet das Credential an die Kontrolle über die Domain.

## 4\. Signatur prüfen

Beide Beispiele laden den Schlüssel und prüfen die ES256-Signatur:

```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"])
```

Ein nach der Signatur auch nur um ein Zeichen verändertes Credential scheitert mit einem Signaturfehler.

## 5\. Format prüfen (optional)

Um zu bestätigen, dass das Credential UNTP 0.7.0 folgt, validieren Sie es gegen das offizielle UNTP-Schema:

```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 verlangt außerdem die Kennung der Produktionsstätte und das Herstellungsland. Das Credential enthält sie, wenn der Pass sie erfasst, und lässt sie sonst weg; es ist daher nur für solche Pässe vollständig gültig gegenüber dem UNTP-Schema. Der Demo-Pass validiert ohne Fehler.

## Was eine gültige Signatur belegt

Dass TracePass genau diese Daten für diese Pass-Version ausgestellt hat und niemand sie seitdem verändert hat. Es ist eine did:web-Signatur: Sie belegt die Kontrolle über tracepass.eu, so stark wie HTTPS. Sie ist kein qualifiziertes elektronisches Siegel nach eIDAS.

Sie umfasst nur die öffentliche Ansicht des Passes, nie eingeschränkte oder behördliche Felder, daher ist sie nicht der vollständige rechtliche Datensatz. Eine Widerrufsliste gibt es noch nicht: Eine bereits gespeicherte Kopie lässt sich auch nach dem Aussetzen eines Passes weiter prüfen. Den aktuellen Status zeigt der Live-Pass.

Probieren Sie es am Demo-Pass, <https://id.tracepass.eu/01/99999999999997/21/6B27A0000001>, oder an jedem veröffentlichten Pass, dessen URL Sie haben.
