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

When using auth wrapper in middleware.ts, the behavior is not as expected #11810

Open
ks4na opened this issue Sep 11, 2024 · 1 comment
Open
Labels
bug Something isn't working triage Unseen or unconfirmed by a maintainer yet. Provide extra information in the meantime.

Comments

@ks4na
Copy link

ks4na commented Sep 11, 2024

Environment

System:
    OS: Linux 5.15 Ubuntu 20.04 LTS (Focal Fossa)
    CPU: (6) x64 Intel(R) Core(TM) i5-9400F CPU @ 2.90GHz
    Memory: 4.23 GB / 7.73 GB
    Container: Yes
    Shell: 5.8 - /bin/zsh
  Binaries:
    Node: 18.18.2 - ~/.nvm/versions/node/v18.18.2/bin/node
    npm: 9.8.1 - ~/.nvm/versions/node/v18.18.2/bin/npm
    pnpm: 8.10.0 - ~/.nvm/versions/node/v18.18.2/bin/pnpm
  npmPackages:
    next: 15.0.0-canary.56 => 15.0.0-canary.56 
    next-auth: 5.0.0-beta.18 => 5.0.0-beta.18 
    react: 19.0.0-rc-f38c22b244-20240704 => 19.0.0-rc-f38c22b244-20240704 

Reproduction URL

https://github.com/ks4na/nextjs-dashboard/tree/f-auth-wrapper

Describe the issue

Hello, I’m experiencing some confusion with using auth wrapper in middleware.ts.

If I don’t use the auth wrapper in middleware.ts and simply export default auth;, visiting /dashboard without logging in correctly redirects me to /login, as expected based on the logic in auth.config.ts -> authConfig.callbacks.authorized. However, when using the auth wrapper, I can access /dashboard without logging in, and the callbacks.authorized function does not seem to work as expected.

It seems that the issue is related to the implementation in the handleAuth function.

https://github.com/nextauthjs/next-auth/blob/main/packages/next-auth/src/lib/index.ts#L230-L286

The order of the two else if statements might need to be swapped.

I'm uncertain whether this behavior is intentional or if it might be a bug.


Additionally, in the first branch, the authorized variable could be set to true, but it appears that this variable is not used later in the handleAuth function, I’m wondering if the logic to "prevent an infinite loop" will still work as intended. I haven’t tested it, just read the code, so please forgive me if I’m wrong.

 if (authorized instanceof Response) {
    // User returned a custom response, like redirecting to a page or 401, respect it
    response = authorized

    const redirect = authorized.headers.get("Location")
    const { pathname } = request.nextUrl
    // If the user is redirecting to the same NextAuth.js action path as the current request,
    // don't allow the redirect to prevent an infinite loop
    if (
      redirect &&
      isSameAuthAction(pathname, new URL(redirect).pathname, config)
    ) {
      authorized = true
    }
  } 

How to reproduce

  1. checkout the source code from Reproduction URL
  2. run pnpm install && pnpm run dev
  3. Visit https://localhost:3000/dashboard, you will not be redirected to the /login page, which is not expected since you should be redirected to /login.
  4. Modify middleware.ts: comment out export default auth(async function middleware(req: NextRequest) { function, and uncomment export default auth; line, then save the changes.
  5. Return to the browser, refresh the page, and you will be redirected to /login since you haven’t logged in. It’s the expected behavior.

Expected behavior

when using auth wrappercallbacks.authorized works as expected.

@ks4na ks4na added bug Something isn't working triage Unseen or unconfirmed by a maintainer yet. Provide extra information in the meantime. labels Sep 11, 2024
@Ali-Raza764
Copy link

If you are simply trying to make the middleware work then you will have to do some custom work. I created middleware in my application in two ways you can check which one works for you.

  1. Use the token to check it the user is authenticated:
import { getToken } from "next-auth/jwt";

export async function middleware(req) {
  const token = await getToken({
    req,
    secret: process.env.AUTH_SECRET,
    // secureCookie: true,
  });

  if (!token) {
    // Redirect to sign-in page if the token is not found
    return NextResponse.redirect(new URL("/", req.url));
  }

  return NextResponse.next();
}

export const config = {
  matcher: ["/profile", "/puzzles"],
};

Make sure to set secureCookie: true in production and comment it in development.

  1. Second way was to use the auth() helper but it sometimes fails when it is deployed to production in vercel:
import { auth } from './auth';


export default auth((req) => {
 const { nextUrl } = req;

 const isAuthenticated = !!req.auth;
 const isPublicRoute = PUBLIC_ROUTES.includes(nextUrl.pathname);

 if (isPublicRoute && isAuthenticated)
  return Response.redirect(new URL(DEFAULT_REDIRECT, nextUrl));

 if (!isAuthenticated && !isPublicRoute)
  return Response.redirect(new URL(ROOT, nextUrl));
});

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

Routes:

export const ROOT = '/';
export const PUBLIC_ROUTES = ['/'];
export const DEFAULT_REDIRECT = '/profile';

To be honest I am not sure why the second approach fails sometimes but these above are the methods I used to handle the middleware.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working triage Unseen or unconfirmed by a maintainer yet. Provide extra information in the meantime.
Projects
None yet
Development

No branches or pull requests

2 participants