Skip to content

feat(auth): server-side session validation helper for custom API routes #643

@Vallhalen

Description

@Vallhalen

Problem

When building custom API endpoints in an EmDash site (e.g., /api/leads, /api/brief-upload), there is no way to validate whether a request comes from an authenticated admin session.

Currently developers resort to checking cookie names:

// INSECURE - only checks if cookie NAME exists, not its value
const cookie = request.headers.get("cookie") || "";
const isAdmin = cookie.includes("astro-session");

An attacker can bypass this with Cookie: astro-session=fake.

Security impact

This was identified during a security audit (RAPTOR framework). Any custom API route that needs admin-only access has no secure way to validate sessions without direct database queries against EmDash's internal session tables.

Proposed solution

Export a session validation helper from the emdash package:

import { validateSession } from "emdash/auth";

export const GET: APIRoute = async ({ request, locals }) => {
  const user = await validateSession(request, locals.emdash);
  if (!user) return new Response("Unauthorized", { status: 401 });
  // user.id, user.email, user.role available
};

Or provide a middleware/guard:

import { requireAdmin } from "emdash/auth";

export const GET: APIRoute = requireAdmin(async ({ request }) => {
  // Only reaches here if session is valid admin
});

Current workaround

// Validate session value length (not just name) - still fragile
const match = cookie.match(/astro-session=([^;]+)/);
const isAdmin = match && match[1] && match[1].length >= 20;

This is better than name-only check but still doesn't verify the session against the database.

Environment

  • EmDash 0.5.0
  • Cloudflare Workers deployment
  • Custom API routes in src/pages/api/

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions