Demo, all content is generated
Question

middleware.ts crashes: The edge runtime does not support Node.js 'crypto' module

Solved · 421 views · asked by ben_ts · edited

I have my own login with JWT cookies (jsonwebtoken package). Windsurf moved the token check into middleware.ts to protect /app routes. Now:

Error: The edge runtime does not support Node.js 'crypto' module.
Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime

The same verify code works fine in my API routes.

What I’ve tried

Windsurf tried adding import crypto from 'crypto' at the top of middleware, then a polyfill package. Both fail.

Comment
Which Next.js version? amir_h · edited

2 answers

Marked as helpful by the asker
amir_h · edited

Middleware has historically run on the Edge runtime, which has Web APIs but not Node's crypto. jsonwebtoken needs Node's crypto. Your API routes run on Node, that's why they work.

Cleanest fix: use jose, which is built on Web Crypto and works in both runtimes:

import { jwtVerify } from "jose";

const secret = new TextEncoder().encode(process.env.JWT_SECRET);

export async function middleware(req: NextRequest) {
  const token = req.cookies.get("session")?.value;
  if (!token) return NextResponse.redirect(new URL("/login", req.url));
  try {
    await jwtVerify(token, secret);
    return NextResponse.next();
  } catch {
    return NextResponse.redirect(new URL("/login", req.url));
  }
}

Which Next version are you on? From 15.5 you can set export const config = { runtime: "nodejs" } in middleware, and in Next 16 the file is proxy.ts and runs on Node by default. But jose is the smaller change and works everywhere.

Comment
15.3. Swapped to jose, 10 lines changed, works. Also replaced jsonwebtoken in the API routes so there's only one library. ben_ts · edited
Good call. Make sure you pass algorithms: ['HS256'] in jwtVerify options too, don't let the token pick its own algorithm. amir_h · edited
chidi_eze · edited

The jose swap is right. Bigger picture though: homemade JWT auth is where AI-generated apps get into trouble (no rotation, no revocation, secrets in the wrong place). If you're early, consider moving to Supabase Auth or Auth.js and let them handle sessions.

Comment
Fair. It's an internal tool for 5 people, but I'll keep it in mind if it grows. ben_ts · edited
Agree with chidi. For 5 internal users what you have is fine once the algorithm is pinned. amir_h · edited