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

Entire site withAuth middleware with custom login routes #4848

Closed
justinforlenza opened this issue Jul 5, 2022 · 15 comments · Fixed by #5000
Closed

Entire site withAuth middleware with custom login routes #4848

justinforlenza opened this issue Jul 5, 2022 · 15 comments · Fixed by #5000
Labels
bug Something isn't working middleware Related to middleware

Comments

@justinforlenza
Copy link
Contributor

justinforlenza commented Jul 5, 2022

Environment

System:
OS: Linux 5.15 Ubuntu 20.04.4 LTS (Focal Fossa)
CPU: (16) x64 AMD EPYC 7B13
Memory: 13.58 GB / 62.81 GB
Container: Yes
Shell: 5.0.17 - /bin/bash
Binaries:
Node: 16.15.1 - ~/.nvm/versions/node/v16.15.1/bin/node
Yarn: 1.22.19 - ~/.nvm/versions/node/v16.15.1/bin/yarn
npm: 8.11.0 - ~/.nvm/versions/node/v16.15.1/bin/npm
npmPackages:
next: 12.1.7-canary.51 => 12.1.7-canary.51
next-auth: latest => 4.8.0
react: ^18 => 18.2.0

Reproduction URL

https://github.com/justinforlenza/nextauth-example

Describe the issue

When using the middleware to require users to login (For entire site not just specific matches) with custom login routes. It causes syntax errors because JS files are being returned as the index html file

Screenshot from 2022-07-05 16-17-04

How to reproduce

  1. Setup custom login routes
  2. Add withAuth middleware for entire site
  3. Load site
  4. See errors in console

Expected behavior

User should be presented with login page when not authenticated

@justinforlenza justinforlenza added the triage Unseen or unconfirmed by a maintainer yet. Provide extra information in the meantime. label Jul 5, 2022
@justinforlenza justinforlenza changed the title Global Middleware with Custom Login Routes Entire site withAuth middleware with custom login routes Jul 6, 2022
@benderham
Copy link

I'm also experiencing this issue running v4.8.0. I've also tested all the way back to v4.5.0 which is referenced in the solution to infinite looping discussed here: #4136

My middleware.ts file looks like this currently:

  import { withAuth } from 'next-auth/middleware';
  
  export default withAuth({
	  pages: {
		  signIn: '/login',
	  },
  });

Removing the pages option reverts to the default NextAuth pages which work as expected.

For reference, I'm using the example custom signin screen from the NextAuth docs:

import type { GetServerSideProps, NextPage } from 'next';
import { getCsrfToken } from 'next-auth/react';

type LoginProps = {
	csrfToken: string;
};

const Login: NextPage<LoginProps> = ({ csrfToken }) => {
	return (
		<form method="post" action="/api/auth/callback/credentials">
			<input name="csrfToken" type="hidden" defaultValue={csrfToken} />
			<label>
				Username
				<input name="username" type="text" />
			</label>
			<label>
				Password
				<input name="password" type="password" />
			</label>
			<button type="submit">Sign in</button>
		</form>
	);
};

export default Login;

export const getServerSideProps: GetServerSideProps = async (context) => {
	return {
		props: {
			csrfToken: await getCsrfToken(context),
		},
	};
};

@balazsorban44
Copy link
Member

I have investigated this, and I could reproduce it with just the following:

import { type NextRequest, NextResponse } from "next/server"

export async function middleware(req: NextRequest) {
  if (req.nextUrl.pathname !== "/login") {
    req.nextUrl.pathname = "/login"
    return NextResponse.redirect(req.nextUrl)
  }
}

Which means this is not a NextAuth.js bug, but rather something in Next.js. I notified the team, please keep an eye on a Next.js update on this.

@balazsorban44 balazsorban44 added the upstream The issue dervies from one of next-auth dependencies label Jul 7, 2022
@benderham
Copy link

Thank you for the prompt response @balazsorban44 😄

@mhornung-chwy
Copy link

Thank you @balazsorban44 and @benderham 😄 I'm running into this issue as well. It seems it is blocking the ability to use a custom login page with middleware. Is there an issue reported against NextJS somewhere for tracking purposes? Where should we look for an update?

@balazsorban44
Copy link
Member

So further investigation shows this is because we don't handle requests against /_next any differently and are redirected to /login as well, which should not necessarily return HTML.

This is because Middleware is now invoked against all requests, not just pages.

I'll reopen this for now.

@balazsorban44 balazsorban44 reopened this Jul 8, 2022
@balazsorban44 balazsorban44 added middleware Related to middleware and removed upstream The issue dervies from one of next-auth dependencies labels Jul 8, 2022
@ShaunSpringer
Copy link

If its helpful, I am also encountering this on a custom sign in page

pages: { signIn: "/auth/signin", },

@ShuPink
Copy link

ShuPink commented Jul 9, 2022

As mentioned by @balazsorban44since this is an upstream issue (I misunderstood, sorry), I managed to get this working by downgrading next back to 12.1.6 which still works with the latest version of next-auth (4.9.0), in case anyone else is trying to resolve their dependabot alerts.

@balazsorban44
Copy link
Member

balazsorban44 commented Jul 12, 2022

So I corrected myself, and this is not an upstream issue, but rather the consequence of Next.js running Middleware for all requests, not just for pages, which is a better/more secure default.

Probably the solution here is to bail out early when requests are going to _next here:

return NextResponse.redirect(signInUrl)

@balazsorban44 balazsorban44 removed the triage Unseen or unconfirmed by a maintainer yet. Provide extra information in the meantime. label Jul 12, 2022
@dimbslmh
Copy link

dimbslmh commented Jul 18, 2022

So I corrected myself, and this is not an upstream issue, but rather the consequence of Next.js running Middleware for all requests, not just for pages, which is a better/more secure default.

Probably the solution here is to bail out early when requests are going to _next here:

return NextResponse.redirect(signInUrl)

Yeah, it's running the middleware on all requests because there is no matcher defined.
See: https://next-auth.js.org/configuration/nextjs#basic-usage and https://nextjs.org/docs/advanced-features/middleware#matcher

For now we can do the following:

import { withAuth } from "next-auth/middleware";

export default withAuth({
  callbacks: {
    authorized: async ({ req }) => {
      const pathname = req.nextUrl.pathname;

      if (pathname.startsWith("/_next") || pathname === "/favicon.ico") {
        return true;
      }

      return false;
    },
  },
  pages: {
    signIn: [path_to_custom_signIn_page],
  },
});

Perhaps someone can create a PR to have the condition added to the withAuth middleware.

@benderham
Copy link

Thanks @dimbslmh, I've updated the above to include a check for the token. Without this you cannot pass the login page.

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

export default withAuth({
  callbacks: {
    authorized: async ({ req, token }) => {
      const pathname = req.nextUrl.pathname;

      if (pathname.startsWith('/_next') || pathname === '/favicon.ico')
        return true;

      if (token) return true;

      return false;
    },
  },
  pages: {
    signIn: '/login',
  },
});

@balazsorban44
Copy link
Member

balazsorban44 commented Jul 22, 2022

An experimental version has been released here with a fix: #5000 (comment)

Please give it a try!

@ShuPink
Copy link

ShuPink commented Jul 23, 2022

I tried the experimental version with next@12.2.2 and the below middleware.ts and it works as expected for me 👍

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

export default withAuth({
  pages: {
    signIn: '/',
    signOut: '/auth/signout',
    error: '/auth/error',
  },
});

@bochensamsung
Copy link

Hi I am trying to use middleware to protect every possible route, is there a one line code using matcher to protect any route? Thanks.
I am Trying

export { default } from 'next-auth/middleware';
export const config = {
  matcher: ['/(.*)'],
}

but what shows up is an infinite loop url with error message: "localhost redirected you too many times."

@ethndotsh
Copy link

/:path*

@nauvalyusufaddairy
Copy link

nauvalyusufaddairy commented Jun 26, 2023

import { withAuth } from "next-auth/middleware";


export default withAuth({
  callbacks: {
    authorized: async ({ req, token }) => {
      const pathname = req.url;
      console.log("pathnaem ", pathname);

      if (token) return true;
      if (pathname === "http://localhost:3000/api/login") return true;

      return false;
    },
  },
  pages: {
    signIn: "/login",
    error: "/error",
  },
});

i've done for this issue, i think you use backend at the same nextjs project so the backend url for login page is also blocked with middleware, i suggest define your backend api in withauth authorized callback and return true if login backend url is hit or any api url's to perform login proccess then issue will gone.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working middleware Related to middleware
Projects
None yet
Development

Successfully merging a pull request may close this issue.

10 participants