Open Site Pass

An open QR code standard for signing in to work sites. Any app can show a pass, and any kiosk can read one.

Version 1, November 2026. Free to use under CC BY 4.0.

Contractors sign in at a different site every week, and each one asks for the same details: name, company, mobile, vehicle, Site Safe card. Open Site Pass lets them carry those details in an app and hand them over by showing a QR code. Any app can show a pass, and any sign-in kiosk can read one, whoever made them.

Before writing this we looked for an existing standard. Visitor sign-in products that use QR passes each have their own format that only works inside that product. The general identity standards (W3C Verifiable Credentials, OpenID for Verifiable Presentations, ISO 18013-5 mobile driving licences) need a wallet app and a multi-step exchange, which is more than a tablet at a site gate needs. So this is a small format that any language can read and check with its built-in crypto.

1. What's in the QR code

The QR code holds plain text in three parts joined by dots:

OSP1.<pass>.<signature>
  • OSP1 says it's an Open Site Pass, version 1.
  • <pass> is the pass as JSON, UTF-8, then base64url without padding.
  • <signature> is an ECDSA P-256 signature with SHA-256 over the ASCII text of <pass> (exactly as it appears in the QR code), as the 64-byte r ‖ s form, then base64url without padding. This is the form Web Crypto's crypto.subtle.sign produces.

2. The 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" }
  ]
}
versionAlways 1 for this version.
issuerThe HTTPS origin of whoever signed the pass, e.g. https://timeclock.kiwi. Its keys are found from this.
keyIdWhich of the issuer's keys signed it.
holderIdThe same for one person with one issuer, and different with every other issuer. Lets a site recognise a returning visitor. It must not be an employee number, email or anything else that identifies them elsewhere.
issuedAt, expiresAtISO 8601 times. A pass should last about a minute and must not last more than 15 minutes, so a photo of one is soon useless.
firstName, lastNameTheir name.
companyWho they work for, if they chose to share it.
phoneMobile number, ideally in international form.
emailEmail address.
vehicleRegistrationNumber plate of the vehicle they came in.
documentsCards and certificates: each has type (from the list below), and optionally number, issuer and expiresOn (YYYY-MM-DD).

Required: version, issuer, keyId, holderId, issuedAt, expiresAt, firstName. Everything else is optional and chosen by the holder each time.

Document types

site-safe-passportSite Safe passport
public-liability-insurancePublic liability insurance
electrical-registrationElectrical registration
plumbing-gasfitting-registrationPlumbing, gasfitting or drainlaying registration
forklift-licenceForklift licence (F endorsement)
first-aid-certificateFirst aid certificate
working-at-heightsWorking at heights
confined-spacesConfined spaces
construction-induction-cardConstruction induction card (White Card)
cscs-cardCSCS card

To propose another type, get in touch below. Kiosks keep documents with types they don't know, but don't match them to anything.

3. Issuer keys

Issuers publish their public keys at <issuer>/.well-known/open-site-pass/keys.json:

{
  "keys": [
    {
      "keyId": "2026-11-3fa9c1",
      "publicKey": { "kty": "EC", "crv": "P-256", "x": "…", "y": "…" }
    }
  ]
}

Each publicKey is a JWK, which Web Crypto can load directly. Keep publishing a key for at least a day after you stop signing with it. Timeclock.Kiwi's keys are at https://timeclock.kiwi/.well-known/open-site-pass/keys.json.

4. Rules for kiosks

  1. Check the signature with the issuer's key, and that the pass hasn't expired. Allow up to 2 minutes either side for clock differences.
  2. Only fetch keys from the issuer's own HTTPS origin, and cache them so a pass can be checked offline.
  3. Show the details and the issuer's domain, and let the visitor confirm before anything is saved.
  4. Treat document details as what the holder entered, not as checked. If your site needs it checked, have a person look at the real card.
  5. You may only accept passes from issuers you trust, or accept any HTTPS issuer and show "Verified by <domain>".
  6. Never ask the holder's app for more than the pass carries. The holder chooses what to share.

5. Rules for apps

  1. Make a new pass at least every minute while it's on screen.
  2. Let the holder choose which optional details go in, every time or as a saved choice they can change.
  3. Never put in anything the holder didn't choose, including their employer, location or internal ids.

6. Checking a pass in JavaScript

This is all a kiosk needs, using only the browser's built-in crypto:

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;
}

Using it with Timeclock.Kiwi

Anyone signed in to the Timeclock.Kiwi app can show a pass from My Site Pass, and every Timeclock.Kiwi site sign-in kiosk reads them, including passes from other apps that follow this format.

We are always happy to help.
Reach out to us and we will do our best to make our employee attendance system work for you.