Next.js Discord

Discord Forum

How to prevent authenticated users access custom login page in next-auth

Answered
Forest yellowjacket posted this in #help-forum
Open in Discord
Forest yellowjacketOP
Hi, I need to prevent authenticated users access to the custom login page and I don't know how to make it with best practises.

I use a middleware service for redirecting from the secured pages to the login page when the user is not authenticated. But when the user is authenticated, he can still access the login page.

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

export const config = { matcher: ["/brewstation/:path*"] }


Is possible to add to the middleware some kind of protection rule like this:
if (req.nextUrl.pathname.startsWith('/login') && isAuthenticated) {
    return NextResponse.redirect(new URL('/dashboard', req.url));
  }


how can I get isAuthenticated in my middleware?
Answered by fuma
the default middleware doesn't redirect authenticated users, you can customise its behaviour by using the withAuth wrapper.

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

// pass callbacks
export default withAuth(...)

// or a function
export default withAuth(req) => {
  if (...) return NextResponse.redirect(...)

  return NextResponse.next()
}
View full answer

26 Replies

the default middleware doesn't redirect authenticated users, you can customise its behaviour by using the withAuth wrapper.

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

// pass callbacks
export default withAuth(...)

// or a function
export default withAuth(req) => {
  if (...) return NextResponse.redirect(...)

  return NextResponse.next()
}
Answer
For the second example, the function is only fired if user is authenticated.
You may utilize the auto-complete features of your code editor
config still works, you're only making a change to your middleware
The default export of next-auth/middleware is same as withAuth() without any options
@fuma The default export of `next-auth/middleware` is same as `withAuth()` without any options
Forest yellowjacketOP
I'm sorry, I'm quitly lost 😄 . When I have defined routes in config then next-auth makes redirects to signIn when user is not authenticated. When I add function withAuth, this function is called when config routes are matched. When I add "/login" route to the matcher, behavior is the same like for "brewstation/:path*"
Is even possible to change this behavior? Simply, just fast check if user is authenticated then he cannot access to the /login
so you want to fire the function regardless the user is authenticated or not?
I remember you can use withAuth as a function though
@fuma so you want to fire the function regardless the user is authenticated or not? I remember you can use `withAuth` as a function though
Forest yellowjacketOP
I'm new to React so I don't know what I can do easily or not. Put simply, I wanted to prevent authenticated users from accessing the /login page. I thought that use middleware could be a good practise, but I'm not sure, if it's even possible.
You're correct, it is indeed a good practise. I found this which is what you're currently looking for: https://next-auth.js.org/configuration/nextjs#advanced-usage

I've just done some tests locally with NextAuth to ensure it works.
Always return true in your authorized callback, then you can access the nextauth property in req passed to your function
It's not a React related problem, don't worry
Forest yellowjacketOP
So if I understand, in authorized callback I need to make redirect from /login ?
return true in authorized callback so that your custom middleware function will be invoked every time user sent a request
in your middleware, redirect user if nextauth.token is null
Forest yellowjacketOP
ah, so in this function I check if I am trying to get to the login page
is null? 🤔 If I have token, I am authenticated, so in this case I need redirect from login to the homepage
import { withAuth } from "next-auth/middleware";
import { NextResponse } from "next/server";

const sign_in = "/auth/signin";

const middleware = withAuth(
  (req) => {
    if (req.nextauth.token == null && req.nextUrl.pathname !== sign_in) {
      return NextResponse.redirect(new URL(sign_in, req.url));
    }

    if (req.nextUrl.pathname === sign_in) {
      return NextResponse.redirect(new URL("/dashboard", req.url));
    }

    return NextResponse.next();
  },
  {
    callbacks: {
      authorized: () => true,
    },
  }
);

export default middleware;

export const config = {
  matcher: ["/dashboard/:path*", "/auth/:path*"],
};
Forest yellowjacketOP
🤔 If I add to the matcher my sign_in route /login it starts to be a protected route. So I can't access it if I'm not authenticated. If I'm not authenticated it redirects me to the /login. Then I get TOO_MANY_REDIRECTS err in browser, because it still redirects.
updated
Forest yellowjacketOP
It works finally
in the second if statement is necessary to add && req.nextauth.token != null
because then /login route is not accesible. No token, then redirects to "/"
Full middleware which works well:
import { withAuth } from "next-auth/middleware";
import { getToken } from 'next-auth/jwt'
import { NextRequest, NextResponse } from 'next/server'

const sign_in = "/login";

const middleware = withAuth(
  (req) => {
    if (req.nextauth.token == null && req.nextUrl.pathname !== sign_in) {
      return NextResponse.redirect(new URL(sign_in, req.url));
    }

    if (req.nextauth.token != null && req.nextUrl.pathname === sign_in) {
      return NextResponse.redirect(new URL("/", req.url));
    }

    return NextResponse.next();
  },
  {
    callbacks: {
      authorized: () => true,
    },
  }
);

export default middleware;

export const config = { matcher: ["/brewstation/:path*", "/login"] };
Forest yellowjacketOP
@fuma Thank you very much for help! 🙂