Why can my regular users see my admin page?

Updated
Short answer

Because the admin page is protected by 'is this user logged in' but not 'is this user an admin'. Every vibe-coded app gets this wrong. The fix is adding a role check in the page's server-side auth guard. Hiding the admin link in the nav doesn't fix it — attackers type the URL directly.

This is one of the most common AI-coding-tool bugs — the model knows how to check 'is someone logged in' but often forgets to check 'is this the RIGHT someone'.

**Where the bug lives.** In Next.js, it's usually in your middleware or in the page's auth guard. Look for: ```ts if (!session) redirect('/login'); // ← bug: this only checks logged-in, not admin return <AdminPage />; ```

**The fix.** Add a role check server-side: ```ts if (!session) redirect('/login'); if (session.user.role !== 'admin') redirect('/'); return <AdminPage />; ```

**Common wrong fixes:** - Hiding the admin link in the nav bar. Useless — attackers type `/admin` directly. - Checking role in a client-side effect. Useless — the page renders before the effect runs, leaking data. - Checking role with a URL query parameter like `?admin=true`. Useless — anyone can set that. - Checking role in the component's render function. Useless unless the component is server-rendered AND the check happens before data fetching.

**Where the role data should live.** In your database (Supabase user_metadata or a separate `admins` table), NOT in cookies or JWTs alone. Client-side role storage can be forged.

Securie's scan (launching this year) will test every page in your app by logging in as a non-admin user and trying to access admin routes. Join the list for a week-1 run that flags every leak with the fix.

People also ask