Skip to Content
ReferenceAuthentication

Authentication

Start with --auth to require a 6-digit access code (printed at startup, changes every restart). Sessions persist 24 hours via HttpOnly cookies.

pieeg-server --auth

On startup you’ll see:

╔══════════════════════════════════════╗ ║ DASHBOARD ACCESS CODE ║ ║ Code: 847291 ║ ╚══════════════════════════════════════╝

Flow

  1. User visits the dashboard → sees login form
  2. Enters the 6-digit code → POST /auth with { "code": "847291" }
  3. Server verifies (HMAC timing-safe compare) → sets HttpOnly session cookie
  4. Dashboard requests a WebSocket token → GET /auth/ws-token
  5. WebSocket connects with ?token=<ws-token>

Security Features

FeatureDetail
Rate limitingLockout after failed attempts
HMAC verificationTiming-safe comparison prevents timing attacks
HttpOnly cookiesSession cookies not accessible to JavaScript
Per-restart codesNew 6-digit code generated each server start
24-hour sessionsAutomatic expiry

The access code is printed to the terminal at startup. Share it only with trusted users on your network.

Programmatic Authentication

const dashboardBase = "http://raspberrypi.local:1617"; const wsBase = "ws://raspberrypi.local:1616"; // 1. Authenticate await fetch(`${dashboardBase}/auth`, { method: "POST", headers: { "Content-Type": "application/json" }, credentials: "include", body: JSON.stringify({ code: "847291" }), }); // 2. Get WebSocket token const { token } = await fetch(`${dashboardBase}/auth/ws-token`, { credentials: "include", }).then((r) => r.json()); // 3. Connect const ws = new WebSocket(`${wsBase}?token=${encodeURIComponent(token)}`);