Open Site Pass
Ein offener QR-Code-Standard für die Anmeldung an Arbeitsstätten. Jede App kann einen Pass anzeigen, und jeder Kiosk kann ihn lesen.
Version 1, November 2026. Kostenlos nutzbar unter CC BY 4.0.
Auftragnehmer melden sich jede Woche an einem anderen Standort an, und überall werden dieselben Angaben verlangt: Name, Firma, Mobilnummer, Fahrzeug, Site-Safe-Karte. Mit Open Site Pass tragen sie diese Angaben in einer App bei sich und übergeben sie per QR-Code. Jede App kann einen Pass anzeigen und jeder Anmeldekiosk ihn lesen, egal von welchem Hersteller.
Bevor wir dies schrieben, suchten wir nach einem bestehenden Standard. Besucheranmelde-Produkte mit QR-Pässen haben jeweils ein eigenes Format, das nur im jeweiligen Produkt funktioniert. Die allgemeinen Identitätsstandards (W3C Verifiable Credentials, OpenID for Verifiable Presentations, mobile Führerscheine nach ISO 18013-5) brauchen eine Wallet-App und einen mehrstufigen Austausch, mehr als ein Tablet am Standorttor benötigt. Deshalb ist dies ein kleines Format, das jede Programmiersprache mit ihrer eingebauten Kryptografie lesen und prüfen kann.
1. Was im QR-Code steht
Der QR-Code enthält Klartext in drei durch Punkte verbundenen Teilen:
OSP1.<pass>.<signature> OSP1besagt, dass es ein Open Site Pass in Version 1 ist.<pass>ist der Pass als JSON, UTF-8, dann base64url ohne Auffüllung.<signature>ist eine ECDSA-P-256-Signatur mit SHA-256 über den ASCII-Text von<pass>(genau wie im QR-Code), in der 64-Byte-Form r ‖ s, dann base64url ohne Auffüllung. Diese Form erzeugtcrypto.subtle.signvon Web Crypto.
2. Der Pass
{
"version": 1,
"issuer": "https://timeclock.kiwi",
"keyId": "2026-11-3fa9c1",
"holderId": "b7f3c2e1a94d0c55e1f3b2a8",
"issuedAt": "2026-11-01T09:42:00.000Z",
"expiresAt": "2026-11-01T09:43:00.000Z",
"firstName": "Sam",
"lastName": "Taylor",
"company": "Harbour Electrical Ltd",
"phone": "+64215550142",
"vehicleRegistration": "QKT482",
"documents": [
{ "type": "site-safe-passport", "number": "SS-482913", "expiresOn": "2027-03-31" }
]
} | version | Für diese Version immer 1. |
|---|---|
| issuer | Der HTTPS-Ursprung der Stelle, die den Pass signiert hat, z. B. https://timeclock.kiwi. Darüber werden die Schlüssel gefunden. |
| keyId | Welcher Schlüssel des Ausstellers ihn signiert hat. |
| holderId | Für eine Person bei einem Aussteller gleich, bei jedem anderen Aussteller anders. So erkennt ein Standort wiederkehrende Besucher. Darf keine Personalnummer, E-Mail oder etwas anderes sein, das die Person anderswo identifiziert. |
| issuedAt, expiresAt | ISO-8601-Zeiten. Ein Pass sollte etwa eine Minute gelten und höchstens 15 Minuten, damit ein Foto davon schnell nutzlos wird. |
| firstName, lastName | Der Name. |
| company | Für wen die Person arbeitet, falls sie das teilen möchte. |
| phone | Mobilnummer, am besten im internationalen Format. |
| E-Mail-Adresse. | |
| vehicleRegistration | Kennzeichen des Fahrzeugs, mit dem die Person kam. |
| documents | Karten und Zertifikate: Jedes hat type (aus der Liste unten) und optional number, issuer und expiresOn (JJJJ-MM-TT). |
Erforderlich: version, issuer, keyId, holderId, issuedAt, expiresAt, firstName. Alles andere ist optional und wird vom Inhaber jedes Mal gewählt.
Dokumenttypen
site-safe-passport | Site Safe passport |
|---|---|
public-liability-insurance | Betriebshaftpflichtversicherung |
electrical-registration | Elektriker-Registrierung |
plumbing-gasfitting-registration | Registrierung für Sanitär, Gas oder Entwässerung |
forklift-licence | Staplerschein (F endorsement) |
first-aid-certificate | Erste-Hilfe-Bescheinigung |
working-at-heights | Arbeiten in der Höhe |
confined-spaces | Enge Räume |
construction-induction-card | Bau-Einweisungskarte (White Card) |
cscs-card | CSCS card |
Um einen weiteren Typ vorzuschlagen, kontaktieren Sie uns unten. Kioske behalten Dokumente unbekannter Typen, ordnen sie aber nichts zu.
3. Schlüssel des Ausstellers
Aussteller veröffentlichen ihre öffentlichen Schlüssel unter <issuer>/.well-known/open-site-pass/keys.json:
{
"keys": [
{
"keyId": "2026-11-3fa9c1",
"publicKey": { "kty": "EC", "crv": "P-256", "x": "…", "y": "…" }
}
]
} Jeder publicKey ist ein JWK, den Web Crypto direkt laden kann. Veröffentlichen Sie einen Schlüssel noch mindestens einen Tag, nachdem Sie nicht mehr damit signieren. Die Schlüssel von Timeclock.Kiwi liegen unter https://timeclock.kiwi/.well-known/open-site-pass/keys.json.
4. Regeln für Kioske
- Prüfen Sie die Signatur mit dem Schlüssel des Ausstellers und ob der Pass abgelaufen ist. Lassen Sie bis zu 2 Minuten Spielraum für Uhrenabweichungen.
- Holen Sie Schlüssel nur vom HTTPS-Ursprung des Ausstellers und speichern Sie sie zwischen, damit ein Pass offline geprüft werden kann.
- Zeigen Sie die Angaben und die Domain des Ausstellers an und lassen Sie den Besucher bestätigen, bevor etwas gespeichert wird.
- Behandeln Sie Dokumentangaben als vom Inhaber eingegeben, nicht als geprüft. Muss Ihr Standort sie prüfen, lassen Sie eine Person die echte Karte ansehen.
- Sie können nur Pässe vertrauenswürdiger Aussteller akzeptieren oder jeden HTTPS-Aussteller akzeptieren und „Verified by <domain>“ anzeigen.
- Verlangen Sie von der App des Inhabers nie mehr, als der Pass enthält. Der Inhaber wählt, was er teilt.
5. Regeln für Apps
- Erstellen Sie mindestens jede Minute einen neuen Pass, solange er angezeigt wird.
- Lassen Sie den Inhaber wählen, welche optionalen Angaben hineinkommen, jedes Mal oder als gespeicherte, änderbare Auswahl.
- Fügen Sie nie etwas hinzu, das der Inhaber nicht gewählt hat, auch nicht Arbeitgeber, Standort oder interne IDs.
6. Einen Pass in JavaScript prüfen
Mehr braucht ein Kiosk nicht, nur mit der eingebauten Kryptografie des Browsers:
async function readPass(text, fetchKeys) {
const [prefix, body, signature] = text.split('.');
if (prefix !== 'OSP1') throw new Error('Not a site pass');
const pass = JSON.parse(atob(body.replace(/-/g, '+').replace(/_/g, '/')));
const keys = await fetchKeys(pass.issuer); // GET <issuer>/.well-known/open-site-pass/keys.json
const jwk = keys.find(k => k.keyId === pass.keyId)?.publicKey;
const key = await crypto.subtle.importKey('jwk', jwk, { name: 'ECDSA', namedCurve: 'P-256' }, false, ['verify']);
const fromB64 = s => Uint8Array.from(atob(s.replace(/-/g, '+').replace(/_/g, '/')), c => c.charCodeAt(0));
const ok = await crypto.subtle.verify({ name: 'ECDSA', hash: 'SHA-256' }, key, fromB64(signature), new TextEncoder().encode(body));
const now = Date.now(), slack = 2 * 60 * 1000;
if (!ok || Date.parse(pass.expiresAt) + slack < now) throw new Error('Not valid');
return pass;
} Verwendung mit Timeclock.Kiwi
Wer in der Timeclock.Kiwi-App angemeldet ist, kann einen Pass unter Mein Standortpass anzeigen, und jeder Timeclock.Kiwi-Anmeldekiosk liest sie, auch Pässe anderer Apps, die diesem Format folgen.