7.4 KiB
Administrative authentication foundation
Integrated administrative sign-in
Administrators sign in at /admin/login using the shared credential configured
as ADMIN_AUTH_SECRET. The page submits the credential directly to
POST /api/admin/auth/login; it does not place the credential in a URL or store
it in browser storage.
Successful authentication creates the administrative session cookie and sends
the browser to /admin. The /admin server-side loader validates that cookie
before loading administrative data. A valid session is not sufficient by
itself: the existing /admin IP allowlist remains an additional restriction,
and a valid administrator outside the allowed network is sent to /403.
The administrative interface provides a Sign out control which calls
POST /api/admin/auth/logout, clears the cookie, and returns the browser to
/admin/login. Sessions expire after 20 minutes and expired, invalid, or
missing sessions are redirected to the login page.
Required server-side configuration
The deployment must provide all of the following server-side values:
ADMIN_AUTH_SECRET: a unique high-entropy administrative passphrase of at least 32 characters.ADMIN_SESSION_SECRET: a different unique high-entropy signing key of at least 32 characters.NEXTAUTH_URL: the existing canonical application URL. Administrative login and logout compare the requestOriginwith this server-configured origin.
The administrative values must never use a NEXT_PUBLIC_ prefix or be exposed
to browser JavaScript. Do not commit real values. Missing, short, or identical
administrative secrets fail closed.
Security properties and limitations
- Credentials are derived with Node
scryptand compared withtimingSafeEqual. - Sessions are stateless, versioned HMAC-SHA256 tokens with a 20-minute fixed lifetime and a random nonce.
- The cookie is
HttpOnly,SameSite=Strict, scoped to/, explicitly expires, and isSecurein production. - Login and logout require an exact same-origin
Originmatch againstNEXTAUTH_URL; missing or malformed origins fail closed. - Authentication responses use
Cache-Control: no-store. - Logout clears the browser cookie. Because sessions are stateless, a stolen token can remain valid until its short expiry; later protected routes must continue verifying signature and expiry on every request.
- This is shared-credential authentication. A valid token proves knowledge of the shared credential, not the identity of a named administrator.
- Protecting
/adminprevents its server-side Prisma, storage, and CRM data loading from running without a valid administrative session. It does not by itself protect browser-addressable API routes.
Administrative API protection limitations
The current administrative UI directly uses API routes that do not yet enforce the administrative session, including:
/api/admin/getnewappeals_api/api/admin/getlatestdocuments_api/api/admin/getStatusCountsByAppeal_api/api/admin/getStatusCountsByAppealAndLPA_api
The appeals and documents routes expose paging operations used after the page has loaded. The status routes expose administrative dashboard reads. These routes retain their existing relay token and HMAC behaviour but have no independent administrative-session authorization. A later authorised stage must enforce the administrative session on privileged API routes and account for both browser calls and the existing server-side bootstrap callers.
Storage download and queue actions retain their existing authorization behaviour. The other administrative API and storage limitations described in this section remain open.
Directly observed storage routes include:
/api/file/getrepsblobproxy, which forwards a caller-supplied container using server relay credentials and path signing./api/file/downloadbloband/api/file/createrepcompletemessage_api, which enforce existing path-HMAC checks but not administrative authorization.
Stage 3 deletion controls
Ordinary case and representation deletion through /api/file/deleteblobcase
and /api/file/deleteblobrep now requires a valid NextAuth session whose user
ID matches the requested Azure container. The existing signed-query/HMAC check
also remains required. Requests that fail ownership or HMAC validation are
rejected before the Azure storage deletion operation is called.
Ordinary JSON and multipart uploads through /api/file/upload and
/api/file/uploadsinglefile independently require a valid NextAuth session whose
user ID exactly matches the submitted containerID. The existing upload HMAC
remains mandatory. Missing or unusable sessions, cross-container requests, and
invalid HMACs are rejected before file processing or Azure storage writes.
Administrative cross-container representation deletion uses the dedicated
POST /api/admin/deleteblobrep route. That endpoint independently validates
the administrative session and requires a trusted same-origin request. It also
validates the requested container, case-folder segment, and representation-file
segment before performing deletion.
Administrative cross-container case deletion uses the dedicated
POST /api/admin/deleteblobcase route. That endpoint independently validates
the administrative session, requires a trusted same-origin request, and
validates the requested container and case-folder segment before performing
deletion. It invokes the same existing deleteBlobCase(container, casefolderID) operation as the ordinary endpoint. That operation lists and
deletes blobs in the selected container whose names begin with the supplied
case-folder prefix; it does not delete the Azure container or broaden deletion
to unrelated containers.
Administrative representation JSON unlocking uses the dedicated
POST /api/admin/editRepJson route. That endpoint independently validates the
administrative session, requires a trusted same-origin request, and validates
the requested container and blob path before removing repComplete. The former
/api/file/editRepJson route is retired and no longer performs storage access.
Automated contract verification for the implemented deletion controls has passed, including ordinary ownership/HMAC rejection, administrative method, session, origin and input rejection, zero deletion calls on rejected requests, and exact cross-container helper arguments on success. Live Azure behaviour, browser-level behaviour, and deployment configuration have not been verified by that automated coverage. The other administrative API and storage limitations documented above remain open, and these changes do not establish closure of the overall ITHC finding.
Deployment requirements before production use
The repository does not provide a demonstrated distributed rate-limit service. Administrative login must therefore be protected by an ingress, gateway, WAF, or shared backing service that enforces rate limits consistently across all deployed instances. A process-local limiter is intentionally not used because it would reset on restart and could be bypassed across instances.
The deployment must also ensure NEXTAUTH_URL is the correct canonical HTTPS
origin. Login and logout intentionally do not derive trust from Host or
forwarding headers.
Any future administrative state-changing API must require more than possession of the cookie: it must independently validate the administrative session and enforce same-origin/CSRF protection before performing side effects.