Skip to content

GlueOps/qr-code-generator

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

213 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Signed QR Service (Go)

A tiny Go HTTP service that mints signed, expiring QR codes for approved target URLs.

It exposes two endpoints:

  • GET /v1/signprotected “mint” endpoint that creates a signed, expiring QR request URL
  • GET /v1/qrpublic endpoint that validates the signature + expiration and returns a PNG QR code

Why

QR codes are easy to copy and reuse. This service lets you generate QR codes that:

  • expire after a configurable TTL
  • can only be minted by callers with a bearer token
  • only encode valid http/https URLs (and rejects localhost)

How it works

Signature format:

sig = base64url( HMAC-SHA256(secret, u + "\n" + exp) )

The QR endpoint requires:

  • u = target URL to encode
  • exp = unix timestamp (seconds) when the request expires
  • sig = HMAC signature over u and exp

If the signature is valid and exp is in the future, the service returns a 256×256 PNG QR code encoding the target URL.

Requirements

  • Go 1.23+
  • Environment variables:
    • QR_SIGNING_SECRET — secret key used for HMAC signing
    • QR_MINT_TOKEN — bearer token required to call /v1/sign

Dependencies used:

  • github.com/joho/godotenv (optional .env loading)
  • github.com/skip2/go-qrcode (PNG QR code generation)

Setup

1) Install dependencies

go mod download

2) Configure environment

Create a .env file (or export env vars):

echo "QR_SIGNING_SECRET=$(openssl rand -hex 32)" > .env
echo "QR_MINT_TOKEN=$(openssl rand -hex 16)" >> .env

Then start the server:

go run .

The service listens on:

  • 0.0.0.0:8000

API

GET /v1/sign (protected)

Mint a signed QR request path.

Auth

  • Authorization: Bearer <QR_MINT_TOKEN>

Query params

  • u (string, required): target URL to encode (must be http or https, not localhost)
  • ttl (int, required): time-to-live in seconds (1..86400)

Response

  • 200 text/plain: a relative path like:
/v1/qr?u=<escaped>&exp=<unix>&sig=<base64url>

Example

curl -s \
    -H "Authorization: Bearer $QR_MINT_TOKEN" \
    "http://localhost:8000/v1/sign?u=https://example.com&ttl=300"

GET /v1/qr (public)

Return a PNG QR code after validating signature + expiration.

Query params

  • u (string, required): target URL to encode
  • exp (int, required): unix timestamp when the request expires
  • sig (string, required): base64url HMAC signature

Response

  • 200 image/png: PNG QR code encoding the target URL (256×256)
  • 401: expired or bad signature
  • 400: missing/invalid params or invalid target URL

Example

First mint a signed path:

SIGNED_PATH=$(
  curl -s \
    -H "Authorization: Bearer $QR_MINT_TOKEN" \
    "http://localhost:8000/v1/sign?u=https://example.com&ttl=300"
)
echo "$SIGNED_PATH"

Then fetch the QR image:

curl -s "http://localhost:8000$SIGNED_PATH" -o qr.png
open qr.png  # macOS; use your OS viewer

Validation rules for u

The target URL must:

  • parse successfully
  • use scheme http or https
  • include a host
  • not have hostname localhost

(Other private/internal hostnames are not blocked by default—see “Hardening” below.)

Security notes

  • /v1/sign is protected via a constant-time compare of the Authorization header.
  • /v1/qr uses constant-time comparison on decoded HMAC bytes.
  • Responses for QR images include Cache-Control: no-store.

Project layout

Currently everything lives in main.go.

About

A FastAPI endpoint that creates QR codes based off given URLs

Topics

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors