Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NextJs 14 middleware redirect issue: User Keeps getting redirected to /login after successful Sign-In #59218

Open
1 task done
anni1236012 opened this issue Dec 3, 2023 · 18 comments · May be fixed by #59931
Open
1 task done
Labels
bug Issue was opened via the bug report template. Runtime Related to Node.js or Edge Runtime with Next.js.

Comments

@anni1236012
Copy link

Link to the code that reproduces this issue

https://github.com/anni1236012/nextjsMiddleware

To Reproduce

  1. yarn dev
  2. All pages are protected via middleware except home page.
  3. Click on any link other than home page and it should redirect you to /login.
  4. Now click on login and it will set the sessionToken cookie with value "loggedin". At this stage, user is authenticated and it should allow users to see the protected pages.
  5. Now click on any protected page and you will see the /login page which is not the expected behavior. It should show the protected page immediately after the successful signin. However, it does work after a few seconds and user can see the protected page. I don't know why there is a delay.
nextjs_middleware_issue.mp4

Current vs. Expected behavior

Delayed navigation, looks like all requests are not reaching middleware and served from cache.

Verify canary release

  • I verified that the issue exists in the latest Next.js canary release

Provide environment information

Operating System:
  Platform: linux
  Arch: x64
  Version: #38~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Thu Nov  2 18:01:13 UTC 2
Binaries:
  Node: 20.5.1
  npm: 9.8.0
  Yarn: 1.22.19
  pnpm: N/A
Relevant Packages:
  next: 14.0.4-canary.37
  eslint-config-next: 14.0.3
  react: 18.2.0
  react-dom: 18.2.0
  typescript: 5.3.2
Next.js Config:
  output: N/A

Which area(s) are affected? (Select all that apply)

Middleware / Edge (API routes, runtime)

Additional context

No response

@anni1236012 anni1236012 added the bug Issue was opened via the bug report template. label Dec 3, 2023
@github-actions github-actions bot added the Runtime Related to Node.js or Edge Runtime with Next.js. label Dec 3, 2023
@SuhelMakkad
Copy link

@anni1236012 try setting the status code to 303. One of the reasons it might fail is because of the browser cache.
By default NextResponse.redirect will do a 307, which can be cahced by the browser.

return NextResponse.redirect(new URL("/login", request.url), {
    status: 303,
});

@anni1236012
Copy link
Author

@SuhelMakkad it did not change the behavior.

@SuhelMakkad
Copy link

Interesting 🤔 I am using this exact setup for my app and it works fine. I tried your repo on my local machine, and after the changes it worked. Maybe you need to clear your browser cache.

@yasermazlum
Copy link

I have exactly the same problem, it does not give the expected behaviour for a while

@anni1236012
Copy link
Author

I fixed it with rewrite instead of redirect.

return NextResponse.rewrite(new URL("/login", request.url), {
        status: 303,
      });

@yasermazlum
Copy link

@anni1236012 no, the problem is not solved. a short time still does not give the expected result

@anni1236012 anni1236012 reopened this Dec 7, 2023
@anni1236012
Copy link
Author

@yasermazlum Please share your github link to recreate the issue.

@babpulss
Copy link

try to avoid loading cached page
append random query on querystring
ex) localhost:3000/hello=${Date.now()}

@cyb3rsalih
Copy link

I also stucked at login page, when I debug see that The user object found and returns true response. But the status code is 303

@pedroSoaresll
Copy link

pedroSoaresll commented Jun 21, 2024

At NextJS 15 (canary version) it was fixed, the server middleware is correct changing the browser URL after NextResponse.redirect.

But I guess I found another error when passing a hash parameter /some-url#value-here, the hash parameter is not sending with the redirected URL.

The problem was not completely fixed.

@skychavda
Copy link

I am experiencing an issue with the middleware. I need to route the user based on their role, but the middleware is not able to route properly. Here's the explanation:

I have two roles in my app, manager and staff, and a user can have either of these roles in their respective org.

When the user changes the org using a dropdown in the UI, the middleware is supposed to detect the new selected org and route the user to the corresponding URL. I've written the following logic for this:

if (orgRole === 'manager' && request.nextUrl.pathname.includes('/staff')) {
      const url = request.nextUrl.clone()
      url.pathname = `${orgShortId}/dashboard/manager/app`
      return NextResponse.redirect(url, { status: 303 })
    }

    if (orgRole === 'staff' && request.nextUrl.pathname.includes('/manager')) {
      const url = request.nextUrl.clone()
      url.pathname = `${orgShortId}/dashboard/staff/app`
      return NextResponse.redirect(url, { status: 303 })
    }

However, the issue I'm facing is that the app is not getting routed to the URL as expected; it remains unchanged.

@JohnHuang-CT
Copy link

might need to use router.refresh

@Enzo-PVsyst
Copy link

Enzo-PVsyst commented Aug 6, 2024

I'm facing a similar issue, where in this middleware :

import { NextRequest, NextResponse } from "next/server";
import unauthorizedRoutes from "./utils/routes";
import evaluateTokensStatus from "./utils/evaluateTokens";

export async function middleware(request: NextRequest) {
  let tokensStatus = evaluateTokensStatus();

  const isAuthenticated =
    tokensStatus === "valid" || tokensStatus === "expired";

  const isUnauthorizedRoute = unauthorizedRoutes.some((route) =>
    request.nextUrl.pathname.startsWith(route)
  );

  console.log("isUnauthorizedRoute", isUnauthorizedRoute);
  console.log("isAuthenticated", isAuthenticated);

  if (!isAuthenticated && !isUnauthorizedRoute) {
    return NextResponse.redirect(new URL("/auth/login", request.url), {
      status: 303,
    });
  }

  if (isAuthenticated && isUnauthorizedRoute) {
    console.log("should redirect to /");
    return NextResponse.redirect(new URL("/", request.url), {
      status: 303,
    });
  }

  return NextResponse.next();
}

export const config = {
  matcher: ["/((?!api|_next/static|_next/image|.*\\.png$).*)"],
};

When redirect should happen it is not working, and nothing happens.

Strange thing ....

@avalanche-tm
Copy link

avalanche-tm commented Aug 7, 2024

Any solution to this? I have the same issue. NextResponse.redirect doesn't redirect but stays on the same site.
I'm using 14.3.0-canary.30, adding status 303 to redirect doesn't help either.

@skychavda
Copy link

I did one workaround though it is not a perfect solution but it worked fine in my case.

I have one drop-down through which I am changing the orgs in user accounts so when the user switches between orgs I add one line in the click event,

window.location.href = "/"

So here what happens is, the app sends the user to root and nextjs middleware executes the code as per my needs.

I hope this workaround helps you. ✌️

@Gamez0
Copy link

Gamez0 commented Sep 6, 2024

Workaround for all, Type redirectResponse.headers.set("x-middleware-cache", "no-cache"); to set x-middleware-cache to no-cache
Middleware isn't running due to cahce. Seems Vercel team is coming up with the fix but anyone can't wait plz check below.

import { type NextMiddlewareResult } from "next/dist/server/web/types";
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";

export const middleware = async (request: NextRequest): Promise<NextMiddlewareResult> => {
  const cookieHeader = request.headers.get("cookie");
  const cookies = cookieHeader
    ? Object.fromEntries(cookieHeader.split("; ").map((c) => c.split("=")))
    : {};

  const accessToken = cookies["accessToken"];
  const userType = cookies["userType"];

  if (
    request.nextUrl.pathname.startsWith("/profile")
  ) {
    if (!accessToken) {
      const redirectResponse = NextResponse.redirect(new URL("/login", request.url));
      redirectResponse.headers.set("x-middleware-cache", "no-cache"); // Set x-middleware-cache to no-cache
      return redirectResponse;
    }
  }

  if (request.nextUrl.pathname.startsWith("/admin")) {
    if (userType !== "admin") {
      const redirectResponse = NextResponse.redirect(new URL("/", request.url));
      redirectResponse.headers.set("x-middleware-cache", "no-cache"); // Set x-middleware-cache to no-cache
      return redirectResponse;
    }
  }

  const response = NextResponse.next();
  response.headers.set(`x-middleware-cache`, `no-cache`); // Set x-middleware-cache to no-cache
  return response;
};

export const config = {
  matcher: ["/((?!api|_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt).*)"],
};

@lpknv
Copy link

lpknv commented Sep 24, 2024

I'm facing a similar issue, where in this middleware :

import { NextRequest, NextResponse } from "next/server";
import unauthorizedRoutes from "./utils/routes";
import evaluateTokensStatus from "./utils/evaluateTokens";

export async function middleware(request: NextRequest) {
  let tokensStatus = evaluateTokensStatus();

  const isAuthenticated =
    tokensStatus === "valid" || tokensStatus === "expired";

  const isUnauthorizedRoute = unauthorizedRoutes.some((route) =>
    request.nextUrl.pathname.startsWith(route)
  );

  console.log("isUnauthorizedRoute", isUnauthorizedRoute);
  console.log("isAuthenticated", isAuthenticated);

  if (!isAuthenticated && !isUnauthorizedRoute) {
    return NextResponse.redirect(new URL("/auth/login", request.url), {
      status: 303,
    });
  }

  if (isAuthenticated && isUnauthorizedRoute) {
    console.log("should redirect to /");
    return NextResponse.redirect(new URL("/", request.url), {
      status: 303,
    });
  }

  return NextResponse.next();
}

export const config = {
  matcher: ["/((?!api|_next/static|_next/image|.*\\.png$).*)"],
};

When redirect should happen it is not working, and nothing happens.

Strange thing ....

I do have a similar issue following the official docs / guide https://nextjs.org/docs/app/building-your-application/authentication#optimistic-checks-with-middleware-optional. The redirect simply does not work as expected.

@Gamez0
Copy link

Gamez0 commented Sep 25, 2024

@lpknv Try disable middleware cache before you return response using
redirectResponse.headers.set("x-middleware-cache", "no-cache");

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Issue was opened via the bug report template. Runtime Related to Node.js or Edge Runtime with Next.js.
Projects
None yet
Development

Successfully merging a pull request may close this issue.