Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Express Middleware Order and Request Identity

Last updated: 4 Oct 20268 min read
tutorial
IntermediateBy AITrove Editorial

An Express application is an ordered stack of middleware and route handlers. Each handler can end the response, call next to continue, or pass an error into the error path. Registration order therefore changes behavior. Authentication identifies the caller; authorization decides whether that caller may act on a specific resource. A valid session does not automatically grant access to every permit ID. Parsing a body before applying limits or reading an untrusted forwarding header before a trusted proxy boundary can also change the security properties of every later route. The stack should make these dependencies visible. A reviewer route must never depend on a middleware that is registered after it has already sent a response.

Working case

A permit API registers its approval router before authentication. The route reads req.reviewer, finds it undefined, and falls back to a development identity left in a helper. Another route allows any signed-in reviewer to fetch case 81 because it checks only whether a session exists. A logging middleware runs after the router and misses successful requests. The repaired stack sets correlation metadata early, limits and parses JSON, authenticates before mounting the private router, and performs case-level authorization inside the repository operation. A final unmatched-route handler returns 404. The error handler sits after routes and maps failures without disclosing private details.

Implementation boundary

javascript
import express from 'express';
import { requireReviewer, permitService, reportError } from './services.js';

const app = express();
app.use(express.json({ limit: '47kb' }));
app.use('/api/permits', requireReviewer);
app.get('/api/permits/:caseId', async (request, response) => {
  const caseId = Number(request.params.caseId);
  if (!Number.isSafeInteger(caseId) || caseId < 1) return response.sendStatus(400);
  const permit = await permitService.findAuthorized(request.reviewer.id, caseId);
  if (!permit) return response.sendStatus(404);
  response.json({ id: permit.id, title: permit.title, status: permit.status });
});
app.use((request, response) => response.sendStatus(404));
app.use((error, request, response, next) => {
  reportError(error, request);
  if (response.headersSent) return next(error);
  response.status(500).json({ message: 'Request failed' });
});

Write down each route's prerequisites and register them before the route. Validate the deployment's proxy trust settings before using forwarded host, scheme, or client IP; an attacker-supplied header is not an identity. Apply body limits and content-type checks before processing private commands. Authentication middleware should resolve a server-owned reviewer object or stop with 401. In the route, validate the case ID, ask a service to verify permission for that reviewer and case, and return a controlled 403 or 404 according to the product's disclosure rule. Keep authorization in the service as well if other callers can reach it. Register a 404 handler after routes and a four-argument error handler last. Test both matching and nonmatching paths.

Cost and boundaries

Each middleware adds request work; a session lookup and case permission query may dominate a small route. Moving a check later to save time can be safe only when no earlier handler observes or mutates protected data. Body parsing has memory cost proportional to accepted payload size, so a configured limit matters under hostile traffic. A repeated permission lookup can be batched or cached within one request, but a shared cache needs the full reviewer and permission boundary. Correlation IDs add small header and log cost while making failures traceable. Measure authentication latency, authorization query count, body rejection rate, and the number of requests that reach expensive handlers unnecessarily.

Failure trace

Call the private route without a session, with an expired session, and with a valid reviewer who lacks case permission. None may enter the mutation service as an authorized write. Register a test logger after the router and observe that a successful response bypasses it, then move it before the route. Send malformed JSON and a body above the configured limit; the route must not begin its write. Send forged forwarding headers from an untrusted connection and verify they do not change identity or audit attribution. Request an unknown path and confirm 404 rather than a silent hang. Test an error thrown during permission lookup and inspect the final response.

Verification

  • Private routes run only after authentication.
  • Case-level permission is checked in the service.
  • Unknown paths and route errors end in controlled responses.

Practice drill

Build a private permit router for read and approval paths. Create a middleware sequence diagram before writing code. Add request identity and a bounded JSON parser, then mount authentication and the router. Inside each handler, parse the case ID and call a service that checks the reviewer against that case. Attach a correlation ID to logs and error output without echoing private service messages. Exercise missing identity, wrong-case access, malformed body, oversize body, and a successful request. Reorder the authentication middleware deliberately in a negative test; restore it after showing the failed invariant.

Decision note

Register middleware in prerequisite order, and authorize the exact resource at the service boundary.

Common Mistakes

  • Registering identity middleware after the route.
  • Treating a valid session as permission for every case.
  • Trusting forwarded headers without a configured proxy boundary.

Related lessons

Express Request and Process Boundaries; Express 5 Async Errors and Response Contracts; Node Request Budgets, Abort, and Event Loop Fairness; Node HTTP Drain, Readiness, and Graceful Shutdown; Authorization and Tenant Boundaries; Ingress Proxy and Upstream Contracts.

Apply and check

Build Project: Express permit API lifecycle and review Web Development: Express request and process quiz.

web-tech
web-development
Storage details