What the barcode carries
A barcode is only a container. The QR Code, for example, is standardised as ISO/IEC 18004. Airline boarding passes follow IATA Resolution 792, the Bar Coded Boarding Pass, which defines the data elements a two-dimensional barcode carries; IATA lists PDF417 as the default on printed passes, with Aztec, Data Matrix and QR also allowed. Apple Wallet passes carry a barcode message in one of several formats, including QR, PDF417, Aztec and Code 128. None of these formats decides whether the ticket is real. That depends on what the message says.
There are two broad designs:
- A reference. The barcode holds a ticket number and nothing else. The scanner has to look it up, either in a live database or in a copy of the valid ticket list downloaded before the event.
- A self-contained ticket. The barcode holds the ticket’s details plus the issuer’s digital signature over them. The scanner can tell a genuine ticket from a forged one without asking anyone.
Only the second design checks authenticity with no network and no full ticket list on the scanner.
Checking a signed ticket offline
One standard way to package signed claims is a JSON Web Token (RFC 7519). The CBOR Web Token (RFC 8392) is derived from it but encodes the claims in binary CBOR and protects them with COSE. RFC 8392 describes it as a compact means of representing claims, which matters when they have to fit in a barcode.
At the gate, the scanner checks:
- The signature, against an issuer public key it was given before the event. An altered or forged ticket fails here.
- The issuer key ID, so it only trusts keys on its list.
- The event, date and entrance, so a genuine ticket for another show is refused.
- The time window. RFC 7519 says a token must not be accepted on or after the time in its
expclaim. This depends on the scanner’s clock being right. - Whether this ticket ID has been seen before.
That last check is the one a signature cannot do. A copy of a genuine ticket carries the same valid signature. RFC 7519 notes that the jti (JWT ID) claim gives each token a unique identifier that can be used to prevent replay, but only if the verifier remembers which identifiers it has already accepted. The W3C Verifiable Credentials Data Model uses this exact case as its replay example: several people presenting the same event ticket credential could all get in. Its suggested countermeasures include a challenge from the verifier that the holder must include, and a short validity period.
Both ideas appear in ticketing. Google Wallet’s rotating barcodes change periodically using a time-based one-time password, and Google says the reader is programmed to accept only the most recent one, which reduces the risk from screenshots. A ticket can also be bound to a key on the holder’s phone, which then has to sign a fresh challenge from the scanner, so a copied code alone is not enough.
Repeat scans across gates
Each scanner keeps a record of the ticket IDs it has admitted, so a second scan at the same gate is refused straight away. The hard case is two gates that cannot see each other’s records.
- Gates that can talk locally over the venue’s own network or a local mesh can share each scan as it happens, so a ticket admitted at the north gate reads as used at the south gate within moments, with no internet involved.
- Gates that are fully cut off cannot know. If the same ticket is presented at both during that time, both may admit it.
Two practical measures reduce the exposure. Making each ticket valid at one entrance only means a copied code has nowhere else to go. And keeping scan records in a form that merges cleanly, such as a set of scanned ticket IDs that only grows (a simple CRDT), means every scan from every gate survives the merge. When two gates both admitted one ticket, the merge shows it, and the venue’s rules decide what to do.
Syncing scan records afterwards
Every scan should produce a record with the ticket ID, the gate, the scanner, the local time and the result. Give each record its own stable ID, so that when a scanner resends its records after an outage the backend can discard duplicates instead of counting a scan twice. Do not rely on scanner timestamps alone to decide which gate was first, because device clocks drift apart.
When a connection returns, scanners upload their records through the normal offline sync path and the ticketing system stays the system of record. It can then reconcile admissions against sales, flag tickets scanned at more than one gate, and update its counts.
Before the doors open
A scanner works offline only with what it was given beforehand:
- the issuer public keys it should trust, including any new key after a rotation;
- a list of cancelled or refunded ticket IDs, because a signature alone cannot show that a ticket was revoked;
- a correct clock, for time windows and rotating codes;
- a test run with the network switched off, to prove the gate really does not depend on it.