11

The Problem

I'm using Next.js, Prisma, and NextAuth's Email Provider strategy to setup an authentication system. I want to use Next.js middleware to redirect a request if it doesn't contain a valid session. But any use of the middleware, like literally just having a function declared in the middleware.js file, throws this error:

error - (middleware)/node_modules/oidc-token-hash/lib/shake256.js (3:0) @ <unknown>
error - Cannot read properties of undefined (reading 'substr')
null

It logs this error about 5 times. This is the middleware.js file at {root}/middleware.js

import { NextResponse } from 'next/server';

export default function middleware(request) {
  return NextResponse.next();
}

And here is this the node_modules/oidc-token-hash/lib/shake256.js file specified in the error:

const crypto = require('crypto');

const [major, minor] = process.version.substr(1).split('.').map((x) => parseInt(x, 10));
const xofOutputLength = major > 12 || (major === 12 && minor >= 8);
const shake256 = xofOutputLength && crypto.getHashes().includes('shake256');

module.exports = shake256;

Prior to creating this file, the app worked perfectly. I could authentiate via an email link, make simple GET requests to API routes, and do any other functionality. I've never seen this error before. The closest I can guess is that I have some sort of dependency/versioning issue, but I'm using damn near latest versions of Next, React, Prisma, NextAuth, Node, etc.

Perhaps it's worth noting that I'm using React Query? Other than that I have no idea what might be causing this.

Package.json:

{
  "name": "nextjs-starter-auth-sql",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "@next-auth/prisma-adapter": "^1.0.4",
    "@prisma/client": "^4.3.0",
    "bcrypt": "^5.0.1",
    "next": "12.2.5",
    "next-auth": "^4.10.3",
    "nodemailer": "^6.7.8",
    "prop-types": "^15.8.1",
    "react": "18.2.0",
    "react-dom": "18.2.0",
    "react-query": "^3.39.2"
  },
  "devDependencies": {
    "autoprefixer": "^10.4.8",
    "eslint": "^8.23.0",
    "eslint-config-airbnb": "^19.0.4",
    "eslint-config-next": "12.2.5",
    "eslint-plugin-import": "^2.26.0",
    "eslint-plugin-jsx-a11y": "^6.6.1",
    "eslint-plugin-react": "^7.31.1",
    "eslint-plugin-react-hooks": "^4.6.0",
    "postcss": "^8.4.16",
    "prisma": "^4.3.0",
    "tailwindcss": "^3.1.8"
  }
}

Happy to answer any questions you may have. Your help is truly appreciated.

rolias4031
  • 233
  • 2
  • 10
  • in which folder did you set up your middleware? – Yilmaz Sep 04 '22 at 17:20
  • Are you sure this is the whole content of `middleware.js`? I got similar error when indirectly importing `next-auth` in `middleware.js`. Next.js creates a sandbox for the middleware by removing properties of `process`, while some libraries require it. – koral Nov 19 '22 at 10:46

2 Answers2

4

I was running into this issue because I was importing the config from [...nextauth].ts into my middleware.ts module. It seems that the middleware cannot use exports from other modules that also use next-auth.

I was able to solve it by moving the part of the config I needed to its own dedicated module and then importing from that module in [...nextauth].ts and middleware.ts respectively.

Before, not working

// src/pages/api/auth/[...nextauth].ts
import type { AuthOptions } from 'next-auth';
import NextAuth from 'next-auth';
import Auth0Provider from 'next-auth/providers/auth0';

export const authOptions: AuthOptions = {
  pages: {
    signIn: '/auth/signin',
  },
  providers: [/* your providers */],
};

export default NextAuth(authOptions);

// src/middleware.ts
import { withAuth } from 'next-auth/middleware';

//  Cannot import from other modules that depend on `next-auth`.
import { authOptions } from '@/pages/api/auth/[...nextauth]';

export default withAuth({
  pages: authOptions.pages,
});

After, working

// src/config/pages.ts
export const pages = {
  signIn: '/auth/signin',
};
// src/pages/api/auth/[...nextauth].ts
import type { AuthOptions } from 'next-auth';
import NextAuth from 'next-auth';
import Auth0Provider from 'next-auth/providers/auth0';

import { pages } from '@/config/pages';

export default NextAuth({
  pages,
  providers: [/* your providers */],
});
// src/middleware.ts
import { withAuth } from 'next-auth/middleware';

// ✅ Import the static config - does not use `next-auth`.
import { pages } from './config/pages';

export default withAuth({
  pages,
});

nerdyman
  • 380
  • 7
  • 14
  • 2
    This is correct. I'm using the app router with middleware and in my case, I was simply importing a constant that was in a file that used next-auth. I moved the utilities that use next-auth to another page and then the importing worked. – ninsau Aug 08 '23 at 00:59
  • 1
    Thanks man you saved my day, I was looking for an answer since past 2 days. – Azzaz Aug 12 '23 at 21:25
-1

I had a similar problem, I tried several ways including this one in the documentation

Although, the only way I got to solve it was to make downgrade of Nextjs version to "12.1.0".

Remove node_modules folder and package-lock.json, after that reinstall dependencies using command "npm install" with version "next": "12.1.0" in package.json and try again.

Let me know if it worked.

  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Oct 02 '22 at 00:15