mediumLogins, sessions and access

Access Decided by a Value in the Browser

Whether a user can see or do something is decided by a value stored in their own browser.

Why it matters

Anyone can open DevTools and run localStorage.setItem('isAdmin', 'true') or invent a token. Hiding a page or a button on the client is fine for convenience, but if the server does not check the session on every request, the client-side check is the only lock, and it is on the inside of the door.

What it looks like

This is the shape of code that triggers the rule. AI tools produce it because it works, and nothing tells them it is unsafe.

Redirect decided by a token in localStorage
useEffect(() => {
  if (!localStorage.getItem('token')) {
    navigate('/login');
  }
}, []);

The smallest fix

minimal patch
// Keep the client check for UX, but make the server the real gate:
// API route / server action:
const session = await getSession(req);      // verified on the server
if (!session) return res.status(401).end();
if (session.user.role !== 'admin') return res.status(403).end();

The better fix

If you have a few more minutes, this is the approach that holds up as the app grows.

safe alternative
// Use httpOnly cookies set by the server for the session, so the
// browser never holds a token JavaScript can read, and check the
// session in middleware for every protected route.

Let your AI tool fix it

When the scanner finds this in your project, it fills in the file and line for you. This is the prompt it gives you to paste into Claude Code, Cursor or whatever you use.

In [the file] at line [the line number], access is decided from browser storage: [the flagged code]. Keep it only as a UI hint. Make sure every protected API route and page verifies the session on the server and returns 401/403 when it fails, so setting a value in localStorage grants nothing.

How to check the fix worked

1. In DevTools, set the storage value to look logged in or admin, then
   call a protected API route directly. It must return 401 or 403.
2. Log in normally and confirm the same route returns data.

Further reading