Access and configuration

Protect administrative surfaces

Separate high-impact operations, require stronger proof, minimize exposure, log changes, and avoid hidden URLs as the main defense.

Admin pages change users, money, access, and how production behaves. That makes them the most valuable target in the app. And a secret-looking path like /admin-x7f2 is not an authorization system. Anyone who finds the URL in a browser history, a log, or a Slack message gets in.

The stale session problem

Here’s the failure this lesson is really about. An administrator logs in at 9 in the morning and leaves the tab open all day. At 4 in the afternoon their laptop is stolen from a café, unlocked. The thief opens the tab, follows a saved link, and deletes accounts. Nothing asked for fresh proof, because the session from the morning was still valid.

Require the role, on the server

Every admin operation needs an explicit role check in the request handler. Not a hidden route. Not a client-side menu that hides buttons from regular users:

function requireAdmin(req, res, next) {
  if (req.user?.role !== 'admin') return res.status(403).end()
  next()
}

Log in as a normal user and call an admin endpoint with curl. You want a 403 and nothing else:

curl -s -o /dev/null -w '%{http_code}\n' -b 'session=regular-user' -X POST https://app.flaviocopes.com/admin/users/42/delete
# 403

Then require freshness

For high-impact changes, a valid session is not enough. Ask for recent authentication or a second factor, so a long-lived stolen session can’t do the damage:

function requireRecentAuth(req, res, next) {
  const age = Date.now() - req.session.authAt
  if (age > 5 * 60 * 1000) return res.status(401).json({ reauth: true })
  next()
}

app.post('/admin/users/:id/delete', requireAdmin, requireRecentAuth, deleteUser)

The stolen session from the café now gets { "reauth": true } on the delete, and the thief doesn’t know the password. The admin who just logged in five minutes ago gets through without friction. That’s the balance you’re after: everything authorized, the dangerous things also fresh.

Don’t apply this to every admin read, though. Forcing MFA to open a user list makes people hate the tool and find workarounds. Reserve the re-auth step for actions that can’t be undone.

Log, separate, narrow

Record an audit event for every attempt, including the ones that failed. Who, what, which target, when, and the outcome. When something goes wrong, that log is how you find out what happened.

Give administrators a separate account for admin work, so their everyday browsing session carries no admin power. And where you can, narrow the network path: put the admin panel behind a VPN or an IP allowlist so the public internet never sees the login form.

Try this on your own project: pick one destructive admin action. Call it as an ordinary user, as an admin with a session older than five minutes, and as an admin who just re-authenticated. The first two must fail, the third must succeed, and all three must show up in the audit log.

Lesson completed