Reputation: 1
My project uses Authjs for authentication, Ive followed the documentation in splitting the auth file into auth.config and pasted their middleware: https://authjs.dev/guides/edge-compatibility .
import NextAuth from "next-auth";
import authConfig from "@/app/auth.config";
export const { auth: middleware } = NextAuth(authConfig);
However I need to fetch the session on the middlware, which when I try to do, I get the error: Error: The edge runtime does not support Node.js 'crypto' module. Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime
here is my middlware:
import { NextResponse } from "next/server";
// import { jwtVerify } from "jose";
import { auth } from "@/app/api/auth";
import NextAuth from "next-auth";
export async function middleware(request) {
// Error: The edge runtime does not support Node.js 'crypto' module.
const session = await auth();
console.log(session);
return NextResponse.next();
}
// Middleware matcher configuration
export const config = {
matcher: [
"/dashboard/:path*",
"/booking/:path*",
"/",
"/about",
"/contact",
"/admin/:path*",
"/login/:path*",
"/signup/:path*",
],
};
here is the authjs file:
import NextAuth from "next-auth";
import Google from "next-auth/providers/google";
import { MongoDBAdapter } from "@auth/mongodb-adapter";
import client from "./client";
import authConfig from "../auth.config";
const db = client.db(process.env.MONGODB_DB);
// Simple function to get user role from database
// async function getUserRole(email) {
// const user = await db.collection("users").findOne({ email });
// return user?.role || "user";
// }
export const { handlers, signIn, signOut, auth } = NextAuth({
adapter: MongoDBAdapter(client),
secret: process.env.NEXTAUTH_SECRET,
session: {
strategy: "jwt",
maxAge: 30 * 24 * 60 * 60, // 30 days
},
...authConfig,
callbacks: {
async jwt({ token, user, account }) {
// Initial sign in
if (account && user) {
token.accessToken = account.access_token;
token.refreshToken = account.refresh_token;
token.accessTokenExpires = account.expires_at * 1000;
token.userId = user.id;
// token.role = user.role;
}
// Check if token needs refresh
if (token.accessTokenExpires && Date.now() >= token.accessTokenExpires) {
try {
const response = await fetch("https://oauth2.googleapis.com/token", {
headers: { "Content-Type": "application/x-www-form-urlencoded" },
method: "POST",
body: new URLSearchParams({
client_id: process.env.AUTH_GOOGLE_ID,
client_secret: process.env.AUTH_GOOGLE_SECRET,
grant_type: "refresh_token",
refresh_token: token.refreshToken,
}),
});
const tokens = await response.json();
if (!response.ok) throw tokens;
return {
...token,
accessToken: tokens.access_token,
accessTokenExpires: Date.now() + tokens.expires_in * 1000,
refreshToken: tokens.refresh_token ?? token.refreshToken,
};
} catch (error) {
console.error("Error refreshing access token:", error);
return { ...token, error: "RefreshAccessTokenError" };
}
}
// Check for role updates on every request
if (token.userId) {
const currentUser = await db
.collection("users")
.findOne({ email: token.email });
if (currentUser && currentUser.role !== token.role) {
token.role = currentUser.role;
}
}
return token;
},
async session({ session, token }) {
if (token) {
session.user.id = token.userId;
session.user.role = token.role;
session.accessToken = token.accessToken;
session.error = token.error;
}
return session;
},
},
});
here is the auth.config file:
import Google from "next-auth/providers/google";
// import client from "./api/client";
// const db = client.db(process.env.MONGODB_DB); // Define db
// export async function getUserRole(email) {
// const user = await db.collection("users").findOne({ email });
// return user?.role || "user";
// }
export default {
providers: [
Google({
clientId: process.env.AUTH_GOOGLE_ID,
clientSecret: process.env.AUTH_GOOGLE_SECRET,
authorization: {
params: {
prompt: "consent",
access_type: "offline",
response_type: "code",
scope: "openid email profile",
},
},
profile: async (profile) => {
// Get role from database
// const role = await getUserRole(profile.email);
return {
id: profile.sub,
name: profile.name,
email: profile.email,
image: profile.picture,
emailVerified: profile.email_verified ? new Date() : null,
role: "admin",
};
},
}),
],
};
here is the client file:
// This approach is taken from https://github.com/vercel/next.js/tree/canary/examples/with-mongodb
import { MongoClient, ServerApiVersion } from "mongodb";
if (!process.env.MONGO_URI) {
throw new Error('Invalid/Missing environment variable: "MONGO_URI"');
}
const uri = process.env.MONGO_URI;
const options = {
serverApi: {
version: ServerApiVersion.v1,
strict: true,
deprecationErrors: true,
},
};
let client;
if (process.env.NODE_ENV === "development") {
// In development mode, use a global variable so that the value
// is preserved across module reloads caused by HMR (Hot Module Replacement).
if (!global._mongoClient) {
global._mongoClient = new MongoClient(uri, options);
}
client = global._mongoClient;
} else {
// In production mode, it's best to not use a global variable.
client = new MongoClient(uri, options);
}
// Export a module-scoped MongoClient. By doing this in a
// separate module, the client can be shared across functions.
export default client;
Upvotes: 0
Views: 24