Picture QR Code

A serverless, password-gated shared photo album accessed via QR code, using AWS Lambda and S3.

https://github.com/davidbmar/picture_qr_code  ·  private  ·  shipped

What it is

A lightweight web application that creates a temporary, shared photo album. Users scan a QR code to access a landing page, enter a guest password, and can then upload photos directly to an S3 bucket or browse existing ones. It requires no app installation and runs entirely on AWS serverless infrastructure (Lambda + S3).

Features

Quickstart

export ACCESS_PASSWORD="your-guest-password"
export OWNER_PASSCODE="your-private-passcode"
export TOKEN_SECRET="$(openssl rand -hex 32)"
./scripts/deploy.sh
python scripts/make_qr.py "<the-printed-url>" album-qr.png

Architecture

flowchart TD
    User[User Device] -->|Scan QR| Browser[Web Browser]
    Browser -->|HTTP Request| Lambda[AWS Lambda Function URL]
    Lambda -->|Serve HTML/JS| Browser
    Browser -->|Enter Password| Lambda
    Lambda -->|Verify HMAC| Lambda
    Lambda -->|Return Presigned URL| Browser
    Browser -->|Upload Image| S3[(AWS S3 Bucket)]
    Browser -->|List/Get Images| Lambda
    Lambda -->|List Objects| S3
    Lambda -->|Generate Presigned Get| S3
    S3 -->|Image Data| Browser

How it's built

The backend is a single AWS Lambda function exposed via a Function URL, which serves the HTML/JS frontend and handles API requests for authentication and presigned URLs. Photo uploads bypass the Lambda, going directly from the browser to S3 using short-lived presigned URLs. Thumbnails are generated client-side using HTML5 Canvas. Authentication uses stateless HMAC tokens signed by a secret stored in Lambda environment variables.

How it runs

sequenceDiagram
    participant U as User
    participant B as Browser
    participant L as Lambda
    participant S as S3

    U->>B: Scan QR Code
    B->>L: GET / (Load Page)
    L-->>B: Return HTML/JS
    U->>B: Enter Guest Password
    B->>L: POST /auth (Password)
    L->>L: Verify HMAC Token
    L-->>B: Return Session Token
    U->>B: Select Photo
    B->>L: POST /sign-upload (Request Upload URL)
    L->>L: Generate Presigned PUT URL
    L-->>B: Return Presigned URL
    B->>S: PUT Image Data (Direct Upload)
    S-->>B: 200 OK
    B->>B: Generate Thumbnail (Canvas)
    U->>B: View Gallery
    B->>L: GET /images (List)
    L->>S: ListObjectsV2
    S-->>L: Object Keys
    L->>S: CreatePresignedGet (For each)
    L-->>B: Return Image URLs
    B->>S: GET Images
    S-->>B: Image Data

How to apply & reuse

Ideal for events like weddings, parties, or conferences where you want attendees to contribute photos to a central gallery without creating accounts or installing apps. It provides a low-friction way to collect media while maintaining basic access control via passwords.

At a glance

CapabilitiesPhoto UploadPhoto BrowsingAccess ControlQR Code GenerationServerless Hosting
ComponentsLambda FunctionS3 BucketHTML/JS FrontendDeploy ScriptQR Generator Script
TechAWS LambdaAmazon S3PythonHTML5JavaScriptHMAC
Depends onAWS CLIPython 3boto3qrcodepillowpillow-heif
Integrates withAWS IAMWeb Browsers
PatternsServerlessPresigned URLsStateless AuthenticationClient-side Processing
Reuse tagsevent-photo-sharingaws-serverlesslambda-s3no-dbqr-code-access

Repo hygiene

✓ all on main — nothing unmerged.