# Signed QR codes and authenticity

> A signed QR code pairs its payload with a digital signature that a verifying app checks against a trusted public key, proving who issued the code and that it was not altered. The EU Digital COVID Certificate worked this way. Signing proves authenticity, not privacy — the payload remains readable by any scanner.

Source: https://useqr.app/docs/security/signed-qr-codes-and-authenticity · Last reviewed 2026-08-21 · UseQR is free forever, MIT licensed, no signup.

---

## The problem signatures solve

Anyone can generate a QR code claiming anything. A code's visual style, logo and frame
prove nothing — they are trivially copied, which is why
[sticker substitution attacks](/docs/security/qr-code-stickers-placed-over-real-ones) work.
When a code is a ticket, a certificate or a proof of provenance, "does it scan" is the
wrong question; the right one is **"who issued this, and has it been altered?"** — and only
cryptography answers it.

## How a signed QR code works

The payload carries two parts: the claims, and a digital signature over them made with the
issuer's private key. A verifying app holds the corresponding public key and checks, at
scan time, that the signature matches. The common open pattern is JWS/JWT — the same
structure used for web tokens, dropped into a code:

```
header.payload.signature   (base64url, signed with e.g. ES256)
```

Any tampering — a changed seat number, an extended expiry — breaks the signature; a forger
without the private key cannot produce a valid one. What the verifier trusts is the key,
not the pixels.

## The flagship example — the EU Digital COVID Certificate

The largest deployment of signed QR codes to date is well documented and public: the EU
Digital COVID Certificate encoded its claims as CBOR, signed them with COSE, compressed
the result and rendered it as text with the `HC1:` prefix. The detail worth savouring:
it used **base45**, an encoding chosen specifically because its 45-character alphabet fits
QR [alphanumeric mode](/glossary/alphanumeric-mode), which packs about 45% more characters
per code than byte mode — a spec-level optimisation covered in
[data encoding modes](/docs/spec/data-encoding-modes). Verifier apps carried the public
keys of every issuing country and checked signatures offline.

## SQRC — the closed variant

Denso Wave's [SQRC](/glossary/sqrc) takes a proprietary route: a code with a public part
any scanner can read and a private part that only licensed readers holding the right
cryptographic key can decode. That is access control as much as authenticity, and it binds
you to specific hardware and licensing. For most authenticity problems, the open
signature-in-payload pattern does the job without special readers.

## What signing does — and does not — give you

| Property | Signed QR delivers it? |
|---|---|
| Authenticity (who issued it) | Yes |
| Integrity (unaltered since issue) | Yes |
| Privacy (payload hidden) | No — anyone can still read the claims |
| Revocation | Only with extra infrastructure (key or ID blocklists) |
| Protection via ordinary camera apps | No — a stock camera just shows the text |

That last row is the deployment catch: signatures only help where scanning happens in a
**verifier app** that checks them. A door steward with a stock camera app sees gibberish
that "looks official", which is no security at all.

## Build sketch for developers

- Keep claims compact — CBOR or terse JSON. Signature overhead is real: an ES256
  signature alone is **64 raw bytes (~86 base64url characters)**, plus header, which
  pushes codes up several [versions](/docs/reference/qr-code-capacity-table).
- Sign server-side at issue time; verify offline in the app with pinned public keys.
  Key distribution and rotation is the actual hard part — design it first.
- Test the full loop: generate, render, decode, verify — the same discipline as a
  [decode-verify check](/docs/developers/why-verify-that-your-qr-code-decodes), with
  signature validation appended.
- For physical goods, signing pairs naturally with
  [product authentication flows](/docs/ecommerce/qr-code-for-product-authentication);
  for physical substitution attacks, pair with
  [tamper-evident labels](/docs/security/tamper-evident-qr-labels) — a valid signature on
  a relocated sticker is still a valid signature.

## FAQ

### What is a signed QR code?

A code whose payload includes a digital signature made with the issuer's private key. A
verifying app checks the signature against the issuer's public key, proving who created
the code and that its contents have not been changed since.

### Can a signed QR code be faked?

The signature cannot be forged without the issuer's private key. What an attacker can do
is copy a genuine code in its entirety — signing proves origin and integrity, not
uniqueness or placement, so duplication and relocation need separate defences.

### Do signed QR codes work with a normal camera app?

No. A stock camera app just displays the encoded text without checking anything.
Signatures only add security when scanning happens in a verifier app that validates them
against trusted keys.

### What did the EU COVID certificate QR contain?

Health claims encoded as CBOR, signed with COSE by the issuing country, compressed, and
rendered as base45 text with an HC1: prefix. Verifier apps checked the signature offline
against a distributed set of national public keys.

## Try it

- https://useqr.app/json
- https://useqr.app/validate
- https://useqr.app/scan
