Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions app/api/auth/admin-status/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { NextRequest, NextResponse } from 'next/server';

/**
* GET /api/auth/admin-status
*
* Returns whether the caller has a valid server-side admin session.
* Relies on the httpOnly-style cookies set by the admin login flow
* and the Next.js middleware – never trusts client-set localStorage.
*/
export async function GET(request: NextRequest) {
const cookies = request.cookies;
const sessionActive = cookies.get('adminSessionActive')?.value === 'true';
const sessionToken = cookies.get('adminSessionToken')?.value;

const isAdmin = sessionActive && !!sessionToken;
Comment on lines +7 to +15
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Cookie-presence auth check is forgeable (admin spoofing risk).

At Line [12]-[15], isAdmin is derived from client-writable cookie presence/value only. Given app/admin/login/page.tsx (Line 159-160) sets these via document.cookie, an attacker can set both cookies manually and get isAdmin: true. The Line [7]-[8] comment about “httpOnly-style cookies” is also inconsistent with current setters.

🔐 Suggested direction (server-validated session token)
 import { NextRequest, NextResponse } from 'next/server';
+import { verifyAdminSessionToken } from '@/lib/auth/admin-session';

 export async function GET(request: NextRequest) {
-  const cookies = request.cookies;
-  const sessionActive = cookies.get('adminSessionActive')?.value === 'true';
-  const sessionToken = cookies.get('adminSessionToken')?.value;
-
-  const isAdmin = sessionActive && !!sessionToken;
+  const sessionToken = request.cookies.get('adminSessionToken')?.value;
+  const isAdmin = sessionToken
+    ? await verifyAdminSessionToken(sessionToken) // signature + expiry + subject/role checks
+    : false;

   return NextResponse.json({ isAdmin });
 }

Also ensure the login/middleware cookie writers set httpOnly: true, secure: true, and sameSite: 'strict'|'lax' from server headers.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/api/auth/admin-status/route.ts` around lines 7 - 15, The GET handler's
admin check (in function GET) currently trusts client-writable cookies
adminSessionActive and adminSessionToken; replace this with a server-validated
session lookup: accept the adminSessionToken cookie value but verify it against
your session store or token verifier (e.g., validateSessionToken(sessionToken)
or lookupAdminSession(sessionToken)) and derive isAdmin from that verification
instead of mere presence; also change the login/middleware writers to set the
token cookie as HttpOnly, Secure and SameSite (set via server response cookies,
not document.cookie in the client), and update any helpers that read cookies to
expect only server-set httpOnly tokens so client-side spoofing cannot mark
isAdmin true.


return NextResponse.json({ isAdmin });
}
285 changes: 193 additions & 92 deletions app/create/ai-story/page.tsx

Large diffs are not rendered by default.

Loading
Loading