vercel / next.js

The React Framework
https://nextjs.org
MIT License
126.84k stars 26.96k forks source link

[NEXT-1088] After upgrading to 13.3 from 13.2 middleware is not working anymore #48083

Open odincreek opened 1 year ago

odincreek commented 1 year ago

Verify canary release

EDIT: Downgraded to 13.2.4 and it is working again, what could be the issue?

This is my middleware and when I click in my client login component the login button, in the network tab login is pending and doesn't do anything, when i rename middleware.js to middleware.bak and I retry it works, and it was working fine before I updated to 13.3

I hope its a bug or something changed

I'm using the app folder

This is my code:

Provide environment information


import { NextResponse } from 'next/server';

export const config = {
  // matcher solution for public, api, assets and _next exclusion
  matcher: '/((?!api|static|.*\\..*|_next).*)',
};

const maintenance = 'false';

function setAccessTokenCookie(response, accessToken) {
  response.cookies.set('access', accessToken, {
    httpOnly: true,
    maxAge: 10 * 60 * 10, // 10 minutes
  });

  return response;
}

async function refreshAccessToken(request, origin) {
  const refreshCookie = request.cookies.get('refresh')?.value;
  if (!refreshCookie) return null;

  const res = await fetch(process.env.BASE_URL + `/auth/refresh`, {
    headers: { refresh: refreshCookie },
  });

  if (!res.ok) return null;

  const { accessToken } = await res.json();

  return accessToken;
}

async function verifyAccessToken(request, origin) {
  const accessCookie = request.cookies.get('access')?.value;
  const refreshCookie = request.cookies.get('refresh')?.value;

  if (!accessCookie && !refreshCookie) return null;

  const res = await fetch(process.env.BASE_URL + `/auth/verify`, {
    headers: { access: accessCookie, refresh: refreshCookie },
  });

  if (!res.ok) return null;

  const { success } = await res.json();

  return success ?? null;
}

function clearAuthCookies(response) {
  response.cookies.set('auth', 'false');
  response.cookies.set('access', '', {
    httpOnly: true,
    expires: new Date(0),
  });
  response.cookies.set('refresh', '', {
    httpOnly: true,
    expires: new Date(0),
  });
  return response;
}

export async function middleware(request) {
  const { method, pathname, origin } = request.nextUrl;

  if (maintenance === 'true' && pathname !== '/maintenance') {
    return NextResponse.redirect(process.env.SITE_URL + `/maintenance`);
  } else if (maintenance === 'false' && pathname == '/maintenance') {
    return NextResponse.redirect(process.env.SITE_URL + `/`);
  }

  const response = NextResponse.next();
  const refreshCookie = request.cookies.get('refresh')?.value;
  const accessCookie = request.cookies.get('access')?.value;

  let user = await verifyAccessToken(request, origin);

  if (user && refreshCookie) {
    if (pathname.startsWith('/auth/')) {
      response.cookies.set('auth', 'true');
      return NextResponse.redirect(process.env.SITE_URL + `/app/dashboard`);
    }
    response.cookies.set('auth', 'true');
    return NextResponse.next(response);
  } else if (user && !refreshCookie) {
    clearAuthCookies(response);
    if (pathname.startsWith('/app/')) {
      return NextResponse.redirect(process.env.SITE_URL + `/auth/login`);
    }
    return NextResponse.next(response);
  } else if (!user && refreshCookie) {
    let newAccess = await refreshAccessToken(request, origin);

    if (newAccess) {
      try {
        setAccessTokenCookie(response, newAccess);
      } catch (error) {
        clearAuthCookies(response);
        if (pathname.startsWith('/app/')) {
          return NextResponse.redirect(process.env.SITE_URL + `/auth/login`);
        }
        return NextResponse.next(response);
      }
      if (pathname === '/auth/login') {
        response.cookies.set('auth', 'true');
        return NextResponse.redirect(process.env.SITE_URL + `/app/dashboard`);
      }
      return response;
    } else if (!newAccess) {
      clearAuthCookies(response);
      if (pathname.startsWith('/app/')) {
        return NextResponse.redirect(process.env.SITE_URL + `/auth/login`);
      }
      return NextResponse.next(response);
    }
  } else if (!user && !refreshCookie) {
    clearAuthCookies(response);
    if (pathname.startsWith('/app/')) {
      return NextResponse.redirect(process.env.SITE_URL + `/auth/login`);
    }
    response.cookies.set('auth', 'false');
    return NextResponse.next(response);
  }
}

Which area(s) of Next.js are affected? (leave empty if unsure)

App directory (appDir: true), Middleware / Edge (API routes, runtime)

Link to the code that reproduces this issue

N/A

To Reproduce

Upgraded from 13.2 to 13.3

Describe the Bug

My middleware is not working which was working completely fine before update

Expected Behavior

I should be sent to the dashboard page after clicking the login button

Which browser are you using? (if relevant)

No response

How are you deploying your application? (if relevant)

No response

NEXT-1088

Aribaskar-jb commented 1 year ago

Hello, I am new to Next JS and would appreciate your assistance in resolving this issue

kunkuntang commented 1 year ago

It's my first time using Next.js and confusing about the middleware doesn't work

rahuld109 commented 1 year ago

Moving middleware.ts inside the /src worked for me.

My Versions:

  • next: "13.3.0",
  • next-auth: "^4.22.0",
odincreek commented 1 year ago

It's already in /src folder for me, didn't help, perhaps its something else.

Podfelix commented 1 year ago

┌─[zhuxian@zhuxiandeMacBook-Pro] - [~/Documents/projects/learn/next-app] - [Mon Apr 10, 10:03] └─[$]> next info

Operating System:
  Platform: darwin
  Arch: x64
  Version: Darwin Kernel Version 22.4.0: Mon Mar  6 21:00:17 PST 2023; root:xnu-8796.101.5~3/RELEASE_X86_64
Binaries:
  Node: 16.17.1
  npm: 9.6.2
  Yarn: 1.22.19
  pnpm: 8.1.0
Relevant packages:
  next: 13.3.0
  eslint-config-next: 13.3.0
  react: 18.2.0
  react-dom: 18.2.0

warn - Latest canary version not detected, detected: "13.3.0", newest: "13.3.1-canary.3". Please try the latest canary version (npm install next@canary) to confirm the issue still exists before creating a new issue. Read more - https://nextjs.org/docs/messages/opening-an-issue

pjc0247 commented 1 year ago

same here

pjc0247 commented 1 year ago

https://github.com/vercel/next.js/issues/38233

philwolstenholme commented 1 year ago

We're seeing this too, this is our middleware.ts file:

import { NextRequest, NextResponse } from 'next/server';

export const config = {
  matcher: [
    /*
     * Match all request paths except for the ones starting with:
     * - api (API routes)
     * - _next/static (static files)
     * - _next/image (image optimization files)
     * - favicon.ico (favicon file)
     */
    '/((?!api|_next/static|_next/image|favicon.ico).*)'
  ]
};

export function middleware(req: NextRequest) {
  const basicAuth = req.headers.get('Authorization');

  if (basicAuth) {
    const authValue = basicAuth.split(' ')[1];
    // atob is deprecated but Buffer.from is not available in Next.js edge.
    const [user, password] = atob(authValue).split(':');

    if (user === 'XXX' && password === 'XXX') {
      return NextResponse.next();
    }

    return NextResponse.json(
      { error: 'Invalid credentials' },
      { headers: { 'WWW-Authenticate': 'Basic realm="XXX"' }, status: 401 }
    );
  } else {
    return NextResponse.json(
      { error: 'Please enter credentials' },
      { headers: { 'WWW-Authenticate': 'Basic realm="XXX"' }, status: 401 }
    );
  }
}
avmentzer commented 1 year ago

same here

amorey commented 1 year ago

I'm also seeing the same behavior with Next.js 13.3.X using this simple set up:

// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export async function middleware(request: NextRequest) {
  const response = NextResponse.next();
  response.headers.set('x-from-middleware', 'hello');
  return response;
}
// pages/index.tsx
import type { GetServerSideProps } from 'next';

export const getServerSideProps: GetServerSideProps = async ({ res }) => {
  console.log(res.getHeader('x-from-middleware'));
  return { props: { } };
}

export default function Home() {
  return <h1>index.ts</h1>;
}

The x-from-middleware header that is set in middleware.ts is reported as undefined in pages/index.ts.

I'm only seeing this behavior with the dev server. When I build and run the production server locally using npm start, I can access the response header in pages/index.ts.

amorey commented 1 year ago

@swve That's an upgrade guide for Next.js v12.2, not v13.3+.

ehowey commented 1 year ago

Seeing this too...

philwolstenholme commented 1 year ago

This might not be the case for everyone, but for me my only middleware issue turned out to be this one: https://github.com/vercel/next.js/issues/48713

Tasin5541 commented 1 year ago

Moving middleware.ts inside the /src worked for me.

My Versions:

  • next: "13.3.0",
  • next-auth: "^4.22.0",

Can verify this is working for me on 13.4.2 for next-auth after moving it inside /src

amorey commented 1 year ago

@ijjk Any updates on this issue?

aamancio commented 1 year ago

Yeah, I'm having the same with this simple setup.

export { default } from "next-auth/middleware";

export const config = { matcher: ["/home"] };
brucemckayone commented 1 year ago

Also having the same problem ill post if i find anything that works

brucemckayone commented 1 year ago

I have partially fixed the issue by adding middleware.ts to tsconfig.json "include": [..., "middleware.ts"]

DenMarty commented 1 year ago

Same problem on 13.4.5

jacobsfletch commented 1 year ago

The fix for me was that I was using both pages and app router simultaneously during incremental adoption:

This is version 13.4.16.

discoverlance-com commented 1 year ago

I am having this issue, even using 13.4.19.

It's quite weird. Anytime I use the config with matcher, the pages just blow up with an error. It works for a while when I use conditional statements to match certain routes but it still blows up after.

Sometimes it works alright for a while and then blows up immediately I make changes and at other times too it blows up when I change to async method, it's just intermittent and blows up in the middleware with the error message below:

This is the client error I keep seeing:

Server Error
Error: Could not find the module "/home/user/project/node_modules/next/dist/client/components/error-boundary.js#" in the React Client Manifest. This is probably a bug in the React Server Components bundler.

Call Stack
resolveClientReferenceMetadata
node_modules/next/dist/compiled/react-server-dom-webpack-experimental/cjs/react-server-dom-webpack-server.edge.development.js (402:12)
resolveClientReferenceMetadata
node_modules/next/dist/compiled/react-server-dom-webpack-experimental/cjs/react-server-dom-webpack-server.edge.development.js (1803:34)
serializeClientReference
node_modules/next/dist/compiled/react-server-dom-webpack-experimental/cjs/react-server-dom-webpack-server.edge.development.js (2181:13)
resolveModelToJSON
node_modules/next/dist/compiled/react-server-dom-webpack-experimental/cjs/react-server-dom-webpack-server.edge.development.js (1412:13)
stringify
<anonymous>
stringify
node_modules/next/dist/compiled/react-server-dom-webpack-experimental/cjs/react-server-dom-webpack-server.edge.development.js (2635:13)
processModelChunk
node_modules/next/dist/compiled/react-server-dom-webpack-experimental/cjs/react-server-dom-webpack-server.edge.development.js (2341:25)
retryTask
node_modules/next/dist/compiled/react-server-dom-webpack-experimental/cjs/react-server-dom-webpack-server.edge.development.js (2388:6)
performWork
node_modules/next/dist/compiled/react-server-dom-webpack-experimental/cjs/react-server-dom-webpack-server.edge.development.js (1707:13)
listOnTimeout
node:internal/timers (569:17)
process.processTimers
node:internal/timers (512:7)
koogawa commented 1 year ago

Moving middleware.ts inside the /repo worked for me. 🙆

Moving middleware.ts inside the /app NOT worked for me. 🙅🏻‍♂️

This is version 13.4.12.

thebiltheory commented 1 year ago

Just for clarification. The middleware needs to be at the same level of your /app directory.

- /src
- - /app
- - middleware.ts
- /app
- middleware.ts

/root
- /src
- - /app
- middleware.ts
mikiU2022 commented 1 year ago

image

▲ Next.js 13.5.4

khashayarghajar commented 1 year ago

same ! in NextJS 14

buroli commented 11 months ago

I'm on the last version of Nextjs (14.0.2) and when I run the project locally with --turbo, isn't working but working without that.

diogenes1oliveira commented 10 months ago

Just to add here because it took me a while to figure it out: if you overrode the pageExtensions in next.config.js you also need to add the corresponding extension to the middleware file. In my case, I had to use src/middleware.page.tsx:

  pageExtensions: ['page.tsx', 'page.ts'],

PS: I'm using the pages/ folder

aktoriukas commented 7 months ago

i found that it was not working because of the

{
   pageExtensions: ["jsx", "mdx", "tsx"]
}

in next.config.js

i think there are few ways to fix this, but in my case i just renamed middleware from .ts to .tsx

pepegc commented 6 days ago

Yeah, I'm having the same with this simple setup.

export { default } from "next-auth/middleware";

export const config = { matcher: ["/home"] };

exact same issue, 14.2.13. App router with src/middleware.ts and src/app/