middleware error 'The edge runtime does not support Node.js 'crypto' module.'
Clumsy-Coder opened this issue · 8 comments
I'm trying to use middleware for protecting routes, but when running the NextJS, it returns an error
NOTE: the middleware is not being used as a edge function. ONLY as a checkpoint for protected routes
packages
- next:
^12.3.0
- iron-session:
^6.2.1
- react:
^18.2.0
file structure
.
├── next-env.d.ts
├── next.config.js
├── package-lock.json
├── package.json
├── public/
├── src
│ ├── components/
│ ├── lib/
│ │ └── AuthSession
│ │ └── index.ts # contains helper functions for iron-session. obtained from iron-session README
│ ├── middleware.ts # middleware used for protecting routes
│ ├── pages
│ │ ├── 404/
│ │ ├── _app.tsx
│ │ ├── _document.tsx
│ │ ├── api/
│ │ │ ├── auth/
│ │ │ │ ├── login.ts # create session using iron-session if the user is authenticated
│ │ │ │ ├── logout.ts # destroy iron-session session
│ │ │ │ ├── session.ts # return iron-session if authenticated, else return empty strings
│ │ │ │ └── unauthorized.ts # return message the request url is unauthorized
│ │ │ └── summary.ts # get summary of a system. REQUIRES authentication
│ │ └── index.tsx
│ └── utils/
├── tsconfig.json
└── tsconfig.tsbuildinfo
21 directories, 43 files
files
src/lib/AuthSession/index.ts
/* eslint-disable @typescript-eslint/return-await */
/* eslint-disable @typescript-eslint/no-unsafe-return */
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-explicit-any */
// this file is a wrapper with defaults to be used in both API routes and `getServerSideProps` functions
import type { IronSessionOptions } from 'iron-session';
import { withIronSessionApiRoute, withIronSessionSsr } from 'iron-session/next';
import {
GetServerSidePropsContext,
GetServerSidePropsResult,
NextApiHandler,
NextApiRequest,
} from 'next';
/**
* Iron session data format to be used
*/
export interface IAuthSession {
ipAddress: string;
port: string;
password: string;
}
const ironSessionTTL = 30 * 60;
/**
* Iron session configs
*/
export const sessionOptions: IronSessionOptions = {
// eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style
password: process.env.SECRET_COOKIE_PASSWORD as string,
cookieName: 'iron-session/pihole/auth',
ttl: ironSessionTTL,
// https://github.com/vvo/iron-session#ironoptions
cookieOptions: {
// secure: true should be used in production (HTTPS) but can't be used in development (HTTP)
secure: process.env.NODE_ENV === 'production',
// https://github.com/vvo/iron-session#session-cookies
// maxAge: undefined // session expires when closing window/tab.
},
};
// This is where we specify the typings of req.session.*
declare module 'iron-session' {
interface IronSessionData {
authSession: IAuthSession;
}
}
export function withSessionRoute(handler: NextApiHandler) {
return withIronSessionApiRoute(handler, sessionOptions);
}
export function withSessionSsr<P extends Record<string, unknown> = Record<string, unknown>>(
handler: (
context: GetServerSidePropsContext,
) => GetServerSidePropsResult<P> | Promise<GetServerSidePropsResult<P>>,
) {
return withIronSessionSsr(handler, sessionOptions);
}
src/middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import { getIronSession } from 'iron-session';
import { sessionOptions } from '@lib/AuthSession';
export async function middleware(req: NextRequest) {
const res = NextResponse.next();
const { authSession } = await getIronSession(req, res, sessionOptions);
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (authSession === undefined) {
return NextResponse.redirect(new URL('/api/auth/unauthorized', req.url));
}
return res;
}
export const config = {
matcher: ['/api/summary'],
};
question
Is there a way to use NextJS middleware to protect routes using iron-session
That error is because you are using non-edge version inside your middleware. Refer #537 for discussion.
Changed the code to use import iron-session/edge
. I'm still getting the same issue
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import { getIronSession } from 'iron-session/edge';
import { sessionOptions } from '@lib/AuthSession';
export async function middleware(req: NextRequest) {
const res = NextResponse.next();
const { authSession } = await getIronSession(req, res, sessionOptions);
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (authSession === undefined) {
return NextResponse.redirect(new URL('/api/auth/unauthorized', req.url));
}
return res;
}
export const config = {
matcher: ['/api/summary'],
};
Use a separate lib/AuthSession for edge. You cannot import non edge version, not even transitively.
Use a separate lib/AuthSession for edge. You cannot import non edge version, not even transitively.
?
Did you mean create a duplicate sessionOptions
in middleware.ts
? Is there a reason behind it?
Something like
src/middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import { getIronSession, IronSessionOptions } from 'iron-session/edge';
export const sessionOptions: IronSessionOptions = {
// eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style
password: process.env.SECRET_COOKIE_PASSWORD as string,
cookieName: 'iron-session/pihole/auth',
ttl: 30 * 60,
// https://github.com/vvo/iron-session#ironoptions
cookieOptions: {
// secure: true should be used in production (HTTPS) but can't be used in development (HTTP)
secure: process.env.NODE_ENV === 'production',
// https://github.com/vvo/iron-session#session-cookies
// maxAge: undefined // session expires when closing window/tab.
},
};
export const middleware = async (req: NextRequest) => {
const res = NextResponse.next();
const { authSession } = await getIronSession(req, res, sessionOptions);
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (authSession === undefined) {
return NextResponse.redirect(new URL('/api/auth/unauthorized', req.url));
}
return res;
};
export const config = {
matcher: ['/api/summary'],
};
@Clumsy-Coder I got this fixed by putting sessionOptions on other files.
Not sure why that happen but it work..
Can you give me an example? Thanks.
hi, how did you fixed this issue? cloud you share it? thanks
hi, how did you fixed this issue? cloud you share it? thanks
And my sessionOptions define in /lib/session.ts, and when i use getIronSession in a edge runtime api (/api/chat/get) meet the same error.