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>
  • OSP1 besagt, 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 erzeugt crypto.subtle.sign von 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" }
  ]
}
versionFür diese Version immer 1.
issuerDer HTTPS-Ursprung der Stelle, die den Pass signiert hat, z. B. https://timeclock.kiwi. Darüber werden die Schlüssel gefunden.
keyIdWelcher Schlüssel des Ausstellers ihn signiert hat.
holderIdFü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, expiresAtISO-8601-Zeiten. Ein Pass sollte etwa eine Minute gelten und höchstens 15 Minuten, damit ein Foto davon schnell nutzlos wird.
firstName, lastNameDer Name.
companyFür wen die Person arbeitet, falls sie das teilen möchte.
phoneMobilnummer, am besten im internationalen Format.
emailE-Mail-Adresse.
vehicleRegistrationKennzeichen des Fahrzeugs, mit dem die Person kam.
documentsKarten 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-passportSite Safe passport
public-liability-insuranceBetriebshaftpflichtversicherung
electrical-registrationElektriker-Registrierung
plumbing-gasfitting-registrationRegistrierung für Sanitär, Gas oder Entwässerung
forklift-licenceStaplerschein (F endorsement)
first-aid-certificateErste-Hilfe-Bescheinigung
working-at-heightsArbeiten in der Höhe
confined-spacesEnge Räume
construction-induction-cardBau-Einweisungskarte (White Card)
cscs-cardCSCS 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

  1. 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.
  2. Holen Sie Schlüssel nur vom HTTPS-Ursprung des Ausstellers und speichern Sie sie zwischen, damit ein Pass offline geprüft werden kann.
  3. Zeigen Sie die Angaben und die Domain des Ausstellers an und lassen Sie den Besucher bestätigen, bevor etwas gespeichert wird.
  4. 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.
  5. Sie können nur Pässe vertrauenswürdiger Aussteller akzeptieren oder jeden HTTPS-Aussteller akzeptieren und „Verified by <domain>“ anzeigen.
  6. 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

  1. Erstellen Sie mindestens jede Minute einen neuen Pass, solange er angezeigt wird.
  2. Lassen Sie den Inhaber wählen, welche optionalen Angaben hineinkommen, jedes Mal oder als gespeicherte, änderbare Auswahl.
  3. 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.

Wir helfen Ihnen jederzeit gern.
Melden Sie sich bei uns und wir tun unser Bestes, damit unser Zeiterfassungssystem zu Ihnen passt.