Read Time: 8 minutes
You've seen it happen. Someone screenshots a concert ticket QR code, sends it to five friends, and suddenly the venue has a problem. Or a coupon code gets shared on Reddit and a thousand people redeem it. QR codes are convenient, but they're also trivially easy to copy.
What if they weren't?
This post explores how cryptographic signatures and time-based tokens can make QR codes resistant to copying, screenshot-sharing, and replay attacks. And you can try it yourself—scan the demos below with your phone.
The Problem with Static QR Codes
A traditional QR code is just data encoded as a pattern of squares. Once generated, it never changes. This creates three vulnerabilities:
- Screenshots — Anyone can capture and reshare the code instantly.
- Replay attacks — A code that worked once will work again, forever.
- No verification — There's no way to confirm the code is legitimate and hasn't been tampered with.
For low-stakes uses (linking to a website, sharing contact info), this is fine. For tickets, payments, access control, or identity verification, it's a serious gap.
Solution 1: Time-Limited Codes (TOTP-Style)
You're probably familiar with authenticator apps like Google Authenticator or Authy. They display a 6-digit code that changes every 10 seconds. The same principle can apply to QR codes.
Here's how it works:
- The QR code contains a payload with the current timestamp
- The payload is cryptographically signed with a private key
- The signature proves the code is authentic and unmodified
- The verifier checks that the timestamp is within the valid window
If someone screenshots the code and tries to use it 20 seconds later, it fails. The timestamp in the signed payload is outside the acceptable window.
Try It: The 10-Second QR
Scan with your phone camera
What to try:
- Scan the QR code now — you'll see it's valid
- Note the countdown timer
- Take a screenshot
- Wait for the code to rotate
- Scan your screenshot — it will show as expired
The screenshot became worthless the moment the time window passed.
Solution 2: One-Time Use Codes (Nonce-Based)
Time-limiting stops delayed replays, but what about instant copying? If someone screenshots a code and uses it within the 10-second window, they could still beat the legitimate holder.
One-time use codes solve this. Each code contains a unique identifier (a "nonce"), and the verification system tracks which nonces have been consumed.
Here's the flow:
- The QR code contains a unique nonce in its signed payload
- When scanned, the verifier checks if this nonce has been used before
- If not, it's marked as consumed and the scan succeeds
- Any subsequent scan of the same nonce fails
First scan wins. Everyone else loses.
Try It: First Come, First Served
Scan with your phone camera
What to try:
- Scan the QR code
- If you're first, you'll see a success message with your claim number
- If someone else got there first, you'll see when it was claimed
- Click "Generate New Code" to create a fresh one-time code
This is how modern event tickets work. The first person through the gate consumes the ticket.
Note: This demo runs entirely in your browser without a server, so "claimed" status is stored locally. Scanning from a different browser or device will reset the claim. In production, a server would track claimed codes globally, preventing reuse across all browsers and devices.
The Cryptography Behind It
Both demos rely on the same cryptographic foundation: digital signatures.
A digital signature is created using a private key that only the issuer possesses. Anyone with the corresponding public key can verify the signature is valid, but no one can forge a new signature without the private key.
The signed payload typically includes:
- Subject — Who or what this code is for
- Issued at — When the code was created
- Expires at — When the code becomes invalid
- Nonce — A unique identifier for one-time use tracking
The signature covers all of this data. If an attacker changes any field—even by one character—the signature becomes invalid.
This is the same technology that secures HTTPS, cryptocurrency transactions, and software updates. Applied to QR codes, it creates tokens that are verifiable, tamper-proof, and optionally single-use.
Combining Both Approaches
The strongest protection combines time-limiting with one-time use:
- The code expires after 10 seconds (defeating delayed screenshots)
- The code can only be scanned once (defeating instant copying)
- The signature proves authenticity (defeating forgery)
For high-security applications—building access, financial transactions, identity verification—this layered approach closes most attack vectors.
Physical Considerations
When QR codes are printed rather than displayed on screens, additional techniques come into play:
- Holographic overlays create visual effects that don't photograph well, making scans of copies appear distorted.
- UV-reactive inks add a verification layer invisible to cameras but visible under blacklight.
- Secure substrates like those used in currency make physical reproduction difficult and expensive.
These physical measures complement the cryptographic ones. Together, they create QR codes that are hard to copy digitally and hard to reproduce physically.
Where This Matters
| Use Case | Problem Solved |
|---|---|
| Event tickets | Stop screenshot sharing and scalper fraud |
| Coupons and promotions | Ensure single-use per customer |
| Access control | Building entry, secure areas, equipment |
| Identity verification | Prove presence at a specific time and place |
| Supply chain | Authenticate products, prevent counterfeiting |
| Payments | Time-limited payment requests that can't be replayed |
The Tradeoffs
Nothing is free. Cryptographic QR codes come with constraints:
- Clock synchronization — Time-based codes require reasonably accurate clocks on both the generator and verifier. A few seconds of drift is usually tolerable; minutes of drift breaks the system.
- Online verification — One-time use codes require the verifier to check (and update) a central record of consumed nonces. Offline verification is possible but requires more complex state synchronization.
- QR capacity — Digital signatures add bytes. A typical Ed25519 signature is 64 bytes, plus the payload itself. This limits how much additional data you can encode.
- Complexity — Static QR codes are simple to generate and verify. Cryptographic codes require key management, secure signing infrastructure, and verification systems.
For many use cases, the added security justifies the added complexity. For others, a static QR is perfectly adequate.
Conclusion
The demos above show what's possible when you combine QR codes with cryptographic signatures and time-based tokens. A screenshot becomes worthless after 10 seconds. A shared code can only be claimed once.
These aren't theoretical concepts—they're production-ready techniques used in digital tickets, payment systems, and access control around the world. The question isn't whether they work, but whether your use case needs them.