Overview

The voting system uses a flexible authentication system that supports multiple authentication methods with a clear priority order. This allows for secure production deployments while maintaining ease of development.

Authentication Methods

The system supports three authentication methods, checked in priority order:

  1. Cloudflare Access (Zero Trust) - Highest priority (production)
  2. ADMIN_API_KEY - Fallback for environments without Cloudflare Access
  3. Local Development Bypass - Automatic bypass for local development

Priority Order

Cloudflare Access → ADMIN_API_KEY → Local Dev Bypass → 401 Unauthorized

Cloudflare Access (Zero Trust)

Priority: Highest (checked first)

Cloudflare Access provides enterprise-grade authentication without requiring API keys. When configured, it automatically authenticates users through Cloudflare’s Zero Trust network.

How It Works

Cloudflare Access sets HTTP headers when a user is authenticated:

  • CF-Access-JWT-Assertion: JWT token from Cloudflare
  • CF-Access-Authenticated-User-Email: Email of authenticated user

The system checks for either header to determine authentication status.

Setup

  1. Configure Cloudflare Access:

    • Go to Cloudflare Dashboard → Zero Trust → Access
    • Create an Access Application
    • Add your Worker route (e.g., /admin/*)
    • Configure identity providers (Google, GitHub, email, etc.)
    • Set up policies for who can access
  2. No Code Changes Required:

    • Once configured, Cloudflare automatically injects headers
    • The system automatically detects and uses these headers

Benefits

  • No API keys to manage
  • Enterprise SSO support
  • Automatic user identification
  • Built-in MFA support
  • Audit logging via Cloudflare

When to Use

  • Production deployments
  • Multi-user environments
  • When you need user identification
  • Enterprise/organizational deployments

ADMIN_API_KEY Authentication

Priority: Second (fallback if Cloudflare Access not available)

A simple API key-based authentication for environments where Cloudflare Access is not configured.

How It Works

  1. Set ADMIN_API_KEY as a Cloudflare secret
  2. Include the key in the Authorization header
  3. System validates the key matches

Header Format

The system supports two formats:

Authorization: Bearer YOUR_API_KEY

or

Authorization: YOUR_API_KEY

Setup

Via Wrangler CLI:

wrangler secret put ADMIN_API_KEY

Via Cloudflare Dashboard:

  1. Go to Workers & Pages → Your Worker
  2. Settings → Variables and Secrets
  3. Add secret: ADMIN_API_KEY
  4. Enter your API key value

For Local Development: Add to .dev.vars:

ADMIN_API_KEY=your-secret-key-here

Usage Example

curl -H "Authorization: Bearer YOUR_API_KEY" \
  https://your-worker.workers.dev/admin/elections

Security Considerations

  • Use Strong Keys: Generate a long, random API key
  • Rotate Regularly: Change keys periodically
  • Keep Secret: Never commit keys to version control
  • HTTPS Only: Always use HTTPS in production

When to Use

  • Single-user deployments
  • Development/staging environments
  • When Cloudflare Access is not available
  • API integrations

Local Development Bypass

Priority: Third (only in local development)

For local development, authentication is automatically bypassed when running on:

  • localhost
  • 127.0.0.1
  • *.dev (Wrangler dev tunnel)

This allows developers to test without configuring authentication.

How It Works

The system checks the request hostname:

hostname === 'localhost' || 
hostname === '127.0.0.1' || 
hostname.endsWith('.dev')

If any condition is true, authentication is bypassed.

Security

⚠️ IMPORTANT: This bypass only works in local development. In production (Cloudflare Workers), this bypass is automatically disabled because:

  • Production URLs don’t match these patterns
  • Cloudflare Workers run in a different environment

When to Use

  • Local development only
  • Testing without authentication setup
  • Development workflows

Implementation Details

Middleware

Authentication is enforced via the requireAdmin middleware in src/middleware/auth.ts:

export async function requireAdmin(
  c: Context<{ Bindings: CloudflareBindings }>, 
  next: Next
)

Applied Routes

The middleware is applied to:

  • All /admin/* routes (API endpoints)
  • All /admin routes (UI pages)

Response Format

When authentication fails, the system returns:

{
  "error": "Authentication required",
  "message": "Use Cloudflare Access (Zero Trust) or provide a valid ADMIN_API_KEY in the Authorization header"
}

Status code: 401 Unauthorized

Admin UI Authentication

The admin UI (/admin/* pages) uses the same authentication system but also:

  • Passes the API key to the frontend (if using API key auth)
  • Allows frontend JavaScript to make authenticated API calls
  • Hides the API key when using Cloudflare Access

Frontend API Key Handling

When using API key authentication (not Cloudflare Access), the admin UI:

  1. Receives the API key from the backend
  2. Stores it in memory (not localStorage)
  3. Includes it in API requests via Authorization header
  4. Never exposes it in URLs or logs

Best Practices

Production

  1. Use Cloudflare Access for production deployments
  2. Don’t set ADMIN_API_KEY if using Cloudflare Access
  3. Monitor access logs via Cloudflare dashboard
  4. Set up MFA in Cloudflare Access policies

Development

  1. Use ADMIN_API_KEY for local development
  2. Add to .dev.vars (gitignored)
  3. Never commit secrets to version control
  4. Use different keys for different environments

Security

  1. Rotate keys regularly
  2. Use strong, random keys (32+ characters)
  3. Limit access to necessary personnel
  4. Monitor for unauthorized access
  5. Use HTTPS in all environments

Troubleshooting

”Authentication required” Error

Possible causes:

  1. Cloudflare Access not configured and no ADMIN_API_KEY set
  2. API key incorrect or not included in request
  3. Request not from localhost (in development)

Solutions:

  1. Configure Cloudflare Access OR set ADMIN_API_KEY
  2. Verify API key is correct and in Authorization header
  3. Check request is coming from localhost/127.0.0.1/*.dev

Cloudflare Access Not Working

Check:

  1. Access application is configured correctly
  2. User is in allowed groups/policies
  3. Route matches Access application path
  4. Headers are being set (check in browser DevTools)

API Key Not Working

Check:

  1. Key is set correctly in secrets
  2. Key matches exactly (no extra spaces)
  3. Header format is correct (Bearer TOKEN or TOKEN)
  4. Worker has been redeployed after setting secret

See Also