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
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).
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
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
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.
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
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.
✓ all on main — nothing unmerged.