Skip to content

joswart/secureqr

Repository files navigation

SecureQR

Secure document sharing for Box folders via QR codes. Generate QR codes that link to Box folder content, accessible only to users with verified email addresses on approved domains.

How It Works

  1. Admin connects to Box via OAuth2 and creates a "share" — specifying a Box folder ID and one or more allowed email domains.
  2. A QR code is generated containing a cryptographically signed URL pointing to the SecureQR application.
  3. Users scan the QR code, enter their email, and receive a magic link (passwordless authentication).
  4. If the user's email domain is authorised, they see the Box folder contents rendered via Box UI Elements — powered by a downscoped token from the admin's Box account.

Users never need a Box account. Access is controlled entirely through email domain verification.

Prerequisites

  • Docker and Docker Compose
  • A Box Developer OAuth2 application (Standard OAuth 2.0)
  • An SMTP server for sending magic link emails (or use console output in development)

Quick Start

# Clone and enter the project
cd secureqr

# Create your environment file
cp .env.example .env

Edit .env with your credentials:

# Generate with: openssl rand -hex 32
APP_SECRET=<64-char-hex-string>

# Admin password (min 12 characters)
ADMIN_PASSWORD=<strong-password>

# From Box Developer Console
BOX_CLIENT_ID=<your-client-id>
BOX_CLIENT_SECRET=<your-client-secret>

# Your public-facing URL
BASE_URL=http://localhost:3000

# SMTP (optional in development — emails print to console)
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USER=<user>
SMTP_PASS=<pass>
SMTP_FROM=noreply@yourdomain.com

Start the application:

docker compose up --build

Then open http://localhost:3000.

Box OAuth2 Setup

  1. Go to the Box Developer Console and create a new Custom App.
  2. Select User Authentication (OAuth 2.0) as the authentication method.
  3. Under Configuration, set the Redirect URI to:
    http://localhost:3000/auth/box/callback
    
    (Replace with your BASE_URL in production.)
  4. Copy the Client ID and Client Secret into your .env file.
  5. In the admin dashboard, click Connect to Box to complete the OAuth flow.

Usage

Admin Workflow

  1. Navigate to /admin/login and sign in with your ADMIN_PASSWORD.
  2. Click Connect to Box to authorise the application (one-time setup).
  3. Click Create New Share:
    • Enter the numeric Box Folder ID (visible in the Box web URL).
    • Enter one or more allowed email domains (comma-separated, e.g. acme.com, partner.org).
    • Optionally add a label for the share.
  4. Download or display the generated QR code. The share URL is also available for direct distribution.

User Workflow

  1. Scan the QR code (or open the share URL).
  2. Enter your email address.
  3. Check your inbox for the magic link (expires in 15 minutes, single-use).
  4. Click the link to view the shared Box folder.

Configuration Reference

Variable Required Default Description
APP_SECRET Yes Master secret for key derivation (min 32 chars, use openssl rand -hex 32)
ADMIN_PASSWORD Yes Admin login password (min 12 chars)
BASE_URL No http://localhost:3000 Public-facing URL (must be HTTPS in production)
PORT No 3000 Server listen port
BOX_CLIENT_ID Yes* Box OAuth2 client ID
BOX_CLIENT_SECRET Yes* Box OAuth2 client secret
SMTP_HOST No SMTP server hostname (if unset, emails log to console)
SMTP_PORT No 587 SMTP server port
SMTP_SECURE No false Use TLS for SMTP connection
SMTP_USER No SMTP authentication username
SMTP_PASS No SMTP authentication password
SMTP_FROM No noreply@secureqr.local Sender address for magic link emails
MAGIC_LINK_TTL_MINUTES No 15 Magic link expiry time
MAGIC_LINK_MAX_PER_EMAIL No 5 Max magic links per email per TTL window
SESSION_MAX_AGE_HOURS No 2 User session duration
NODE_ENV No development Set to production for secure cookies and HTTPS enforcement

*Required to use Box features. The app starts without them but Box connect will fail.

Security

Cryptography

  • Key derivation: All keys are derived from a single APP_SECRET using HKDF-SHA256 (RFC 5869) with purpose-specific info labels, ensuring domain separation between encryption, signing, session, and CSRF keys.
  • Token encryption: Box OAuth tokens are encrypted at rest with AES-256-GCM (96-bit random IV, 128-bit auth tag).
  • QR URL signing: Share URLs are signed with HMAC-SHA256 using a purpose-derived key. Signatures are verified with constant-time comparison.
  • Magic link tokens: 256-bit random tokens. Only SHA-256 hashes are stored in the database. Single-use, time-limited.
  • Admin password: Verified with bcrypt (cost factor 12).

Access Control

  • Domain-based authorisation re-validated on every request (not just at login).
  • Session fixation protection via session.regenerate() on all login flows.
  • OAuth state parameter prevents CSRF on the Box connect flow.
  • Anti-enumeration: rejected email domains receive the same response as accepted ones.

Rate Limiting

  • Magic link requests: 5 per IP per 15 minutes.
  • Magic link verification: 10 per IP per 15 minutes.
  • Admin login: 5 per IP per 15 minutes.

HTTP Security

  • Helmet.js security headers (HSTS, X-Frame-Options, X-Content-Type-Options, etc.).
  • Content Security Policy tuned for Box UI Elements CDN.
  • CSRF double-submit cookie on all state-changing endpoints.
  • httpOnly, sameSite=lax, and secure (production) session cookies.

Audit Logging

All security-relevant actions are logged to the audit_log table:

  • Admin login / logout / failed attempts
  • Box OAuth connect and token refresh
  • Share creation and deactivation
  • Magic link creation, verification, and domain rejections
  • Viewer folder access

Development

# Install dependencies
npm install

# Start with auto-reload
npm run dev

Without SMTP configured, magic link emails are printed to the console.

Architecture

src/
├── app.js                    # Express setup, middleware chain
├── server.js                 # HTTP listener
├── config.js                 # Environment validation
├── db/
│   ├── connection.js         # SQLite (WAL mode, foreign keys)
│   └── migrations.js         # Schema: box_tokens, shares, users, magic_links, audit_log
├── middleware/
│   ├── adminAuth.js          # Admin session guard
│   ├── viewerAuth.js         # Viewer session + domain re-check
│   ├── csrf.js               # Double-submit cookie CSRF
│   └── rateLimiter.js        # express-rate-limit configs
├── routes/
│   ├── admin.js              # Dashboard, share CRUD, QR generation
│   ├── auth.js               # Box OAuth callback, magic link flow
│   └── viewer.js             # Folder view, downscoped token API
├── services/
│   ├── crypto.js             # HKDF, AES-256-GCM, HMAC-SHA256
│   ├── boxService.js         # Box SDK, OAuth, token storage, downscoping
│   ├── qrService.js          # QR generation, URL signing
│   ├── tokenService.js       # Magic link lifecycle
│   ├── emailService.js       # Nodemailer wrapper
│   └── audit.js              # Audit log writes
└── views/                    # EJS templates

License

Private — all rights reserved.

About

Create secure QR links to Box folders

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors