Skip to main content

Overview

Sightscreen uses a two-track authentication system:
  1. Cognito JWT — for mobile app users and admin users
  2. Admin API Key — for server-to-server calls and internal tooling
Both tracks converge into a unified middleware chain that populates req.user before handlers execute. Authenticated user context is also attached to Sentry for error tracking.

Cognito JWT validation

All authenticated mobile requests send a Bearer token in the Authorization header. The backend validates it using aws-jwt-verify.
Validation flow:
  1. Extract token from Authorization: Bearer <token> header.
  2. Pass to CognitoJwtVerifier (from aws-jwt-verify) configured with the User Pool ID and Client ID.
  3. The verifier fetches the JWKS (JSON Web Key Set) from Cognito and caches it.
  4. On success, decode claims and build the user object.
  5. On failure, return 401 Unauthorized.
The JWKS is cached in-memory after the first fetch. Cold starts incur one extra network call to Cognito.

Required environment variables


Admin API Key

For server-to-server and internal tooling requests, the backend accepts a static API key.
The key is compared directly against the ADMIN_API_KEY environment variable. If it matches, the request is treated as an admin-level request without needing a Cognito token.
The API key grants full admin access. Rotate it if compromised. Never expose it in client-side code.

Middleware chain

Four middleware functions control access across the route tree:

requireAuth

Requires a valid Cognito JWT. Rejects with 401 if the token is missing or invalid. Populates req.user. Used on all authenticated user endpoints (/me, /matches, /devices, etc.).

optionalAuth

Attempts Cognito JWT validation but does not reject on failure. If a valid token is present, req.user is populated; otherwise req.user is undefined. Used on endpoints that behave differently for authenticated vs. anonymous users.

requireAdmin

Runs after requireAuth. Checks that req.user.isAdmin is true (i.e., the user belongs to the admin Cognito group). Rejects with 403 Forbidden otherwise.

requireAdminOrApiKey

Checks for either:
  • A valid Cognito JWT with admin group membership, or
  • A valid X-API-Key header
This is the gate on all /admin/* routes. It allows both human admins (via Pavilion) and automated systems (via API key) to manage resources.

Sentry integration

After successful authentication, the middleware sets the Sentry user context so that all errors and transactions for the request are tagged with the user identity:
This enables filtering errors by user in the Sentry dashboard and correlating issues with specific accounts. The Sentry context is cleared at the end of each request lifecycle.

User object shape

After successful authentication, req.user contains:
string
required
The Cognito sub claim. Unique identifier for the user.
string
required
The user’s phone number from Cognito claims.
boolean
required
true if the user belongs to the admin Cognito group.
string[]
required
List of Cognito groups the user belongs to (e.g., ["admin"]).

Dev mode bypass

Only active when NODE_ENV=development. Never runs in production.
When running locally, the authentication middleware skips Cognito validation entirely and injects a hardcoded user object: This lets you test endpoints locally without running Cognito infrastructure.