Overview
Sightscreen uses a two-track authentication system:- Cognito JWT — for mobile app users and admin users
- Admin API Key — for server-to-server calls and internal tooling
req.user before handlers execute.
Cognito JWT validation
All authenticated mobile requests send a Bearer token in theAuthorization header. The backend validates it using aws-jwt-verify.
- Extract token from
Authorization: Bearer <token>header. - Pass to
CognitoJwtVerifier(fromaws-jwt-verify) configured with the User Pool ID and Client ID. - The verifier fetches the JWKS (JSON Web Key Set) from Cognito and caches it.
- On success, decode claims and build the user object.
- 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
| Variable | Purpose |
|---|---|
COGNITO_USER_POOL_ID | The Cognito User Pool to validate against |
COGNITO_CLIENT_ID | The App Client ID for token audience validation |
Admin API Key
For server-to-server and internal tooling requests, the backend accepts a static API key.ADMIN_API_KEY environment variable. If it matches, the request is treated as an admin-level request without needing a Cognito token.
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-Keyheader
/admin/* routes. It allows both human admins (via the admin panel) and automated systems (via API key) to manage resources.
User object shape
After successful authentication,req.user contains:
The Cognito
sub claim. Unique identifier for the user.The user’s phone number from Cognito claims.
true if the user belongs to the admin Cognito group.List of Cognito groups the user belongs to (e.g.,
["admin"]).Dev mode bypass
When running locally, the authentication middleware skips Cognito validation entirely and injects a hardcoded user object:| Scenario | Trigger | Injected user |
|---|---|---|
| Dev user | Any request with Authorization: Bearer dev | { userId: "dev-user", phone: "+61400000000", isAdmin: false, groups: [] } |
| Dev admin | Any request with Authorization: Bearer dev-admin | { userId: "dev-admin", phone: "+61400000000", isAdmin: true, groups: ["admin"] } |