Admins (Microsoft 365 sign-in names in BACKUP_DASH_ADMINS) get an
Admin link to /admin.html, where they can create, list and revoke the
API keys collectors use, instead of running manage.py on the server.
Backend
- /api/v1/admin/keys (list, create, revoke), admins only (403
otherwise); the user comes from the headers nginx sets after sign-in
- Changes need an X-Requested-By header, which another site's page
can't add, so a signed-in admin's browser can't be used to forge them
- A new key is returned once; only its hash is stored. Names are unique
for good, so revoked keys' history stays unambiguous
- Keys record who created/revoked them and the company they last
reported for (schema v2; databases migrate automatically on start)
- /api/v1/me reports is_admin; manage.py shares the key code and
records itself as creator/revoker
Frontend
- admin.html / admin.js: name validation shown after interaction
(:user-invalid, aria-invalid kept in sync), the one-time key with a
copy button (falls back to selecting it if clipboard access is
refused), a key table flagging keys quiet for over 24 hours, and
revoking confirmed in a <dialog>; results announced in a status region
- Shared el() and signed-in helpers moved to dom.js / signed-in.js
- Mock mode (?mock=1) includes sample keys
Tested: 15 new backend tests (access, forged requests, names,
duplicates, revoking, last-used company, v1 -> v2 upgrade); in the
browser, every admin flow in mock mode and at phone width; end to end
through the nginx config with the real API (a key created on the API
works for ingest; revoking it makes ingest 401; non-admins see an
explanation and no Admin link).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
nginx now checks every dashboard and API request with oauth2-proxy
(auth_request), which signs users in with Microsoft Entra ID. Who may
sign in is controlled in Entra: a single-tenant app registration with
"Assignment required", so only assigned users/groups get through.
- deploy/oauth2-proxy.cfg (entra-id provider, auth-only mode, secure
cookie, trusted proxy = localhost) and deploy/oauth2-proxy.service
- nginx: pages redirect to Microsoft sign-in and back to the same URL;
API calls get a plain 401 (the page already asks to reload);
/api/v1/ingest stays key-only for collectors; /oauth2/auth is
internal; the signed-in user is passed to the API in headers nginx
sets (so browsers can't spoof them); dashboard files are served with
Cache-Control: no-cache so updates show up at once
- GET /api/v1/me; the top bar shows the signed-in user and a Sign out
that also signs out of Microsoft (otherwise SSO signs straight back in)
- README: Entra and server setup steps
Tested locally with oauth2-proxy 7.15.5 and nginx 1.31 running the
deploy configs (TLS, self-signed): redirects to the tenant's sign-in
with the return URL kept, 401s, ingest bypass, sign-out allow-list,
cookie flags, security headers. The signed-in path was tested with a
stand-in for oauth2-proxy's auth answer; a real Entra sign-in wasn't.
Co-Authored-By: Claude Opus 5.5 <[email protected]>