Next.js Discord

Discord Forum

setting up middleware to authenticate pages

Unanswered
Morelet’s Crocodile posted this in #help-forum
Open in Discord
Morelet’s CrocodileOP
I am trying to authenticate dashboard and its relevant pages on the basis of jwt token that is stored in cookies on login. But even if user is logged in i still get the cookies undefined, even though cookies are set and i can see it in application cookies storage.
How do i add matchers for protected routes?

// middleware.js

import { NextResponse } from 'next/server';
import { USER_AUTH_TOKEN } from './constants';

export async function middleware(request) {
  // Getting the authentication token from cookies
  const authToken = request.cookies.get(USER_AUTH_TOKEN);

  // Check if the route starts with /pdftoolsdashboard
  const isProtectedRoute = request.nextUrl.pathname.startsWith('/pdftoolsdashboard');

  // If the route is protected and there's no authentication token, redirect to the home page
  if (isProtectedRoute && !authToken) {
    return NextResponse.redirect('/');
  }

}


export const config = {
  matcher: '/pdftoolsdashboard/:path*',
}

15 Replies

Morelet’s CrocodileOP
i'm getting the cookie undefined always. even though it exists, @Arinji do you know anything about it?
import { NextResponse } from 'next/server';
import { USER_AUTH_TOKEN } from './constants';

export default  function  middleware(req) {
  let verify =  req.cookies.get('auth_token');
  const url =  req.nextUrl.clone();
  const url2 =  JSON.stringify(url);

  console.log('verify', verify)
  // console.log('url', url)

  if (!verify?.value && url2.includes('/dashboard/pdftoolsdashboard')) {
    console.log('user not authenticated')
    url.pathname = '/dashboard/login';
    return NextResponse.redirect(url);
  }

  // if (verify?.value && url2.includes('/dashboard/signup')) {
  //   url.pathname = '/dashboards/login';
  //   return NextResponse.redirect(url);
  // }
  if (verify?.value && url2.includes('/dashboard/login')) {
    console.log('user authenticated')
    url.pathname = '/dashboard/pdftoolsdashboard';
    return NextResponse.redirect(url);
  }
}

export const config = {
  matcher: '/dashboard/pdftoolsdashboard/:path*',
}
so verify is undefined?
which page are you on
Morelet’s CrocodileOP
@Arinji when i login, the user must be redirected on dashboard/pdftoolsdashboard page if authenticated and i get the token. auth_token is set on login but in middleware i get it undefined. Because of that i stays on login page even if the user is authenticated
Morelet’s CrocodileOP
yes i added a redirect when user is successfully logged in on the login page
i saw someone was also facing this issue but i don't understand the solution
https://github.com/vercel/next.js/discussions/38690
Morelet’s CrocodileOP
const signInhandler = async (data) => {
    setIsLoading(true);
        const response = await postDataApiCall('/api/dashboard/auth/login',data);
        const { error } = response;
        if(!response.error){
            const user = response;
            localStorage.setItem('currentUser' , JSON.stringify(user))
            localStorage.setItem('token' , JSON.stringify(user.token))
            await push('/dashboard/pdftoolsdashboard') //here
            toast.success(`Welcome ${user.userName} `, { position: toast.POSITION.TOP_RIGHT } );
        }else{
            toast.error(`${error}`, { position: toast.POSITION.TOP_RIGHT });
        }
        setIsLoading(false);
    };
The api code as well
Morelet’s CrocodileOP
const bcrypt = require("bcryptjs")
const jwt = require("jsonwebtoken")
import { serialize } from 'cookie';
import { exceptions } from '../../../../libs/exception';
import { responseMessages } from '../../../../libs/messages';
import { getUserByEmail } from '../../../../services/authServices';
import { USER_AUTH_TOKEN } from '../../../../constants';

const handler = async (req, res) => {
  const email = req.body.email;
  const password = req.body.password;

  if (!email || !password) {
    return res
      .status(exceptions.BAD_REQUEST_EXCEPTION)
      .json({ error: responseMessages.MISSING_FIELDS });
  }

  const user = await getUserByEmail(email);
  if (!user) {
    return res
      .status(exceptions.BAD_REQUEST_EXCEPTION)
      .json({ error: responseMessages.ENTER_VALIDE_CREDENTIALS });
  }

  const passwordIsValid = bcrypt.compareSync(password, user.password);
  if (!passwordIsValid) {
    return res
      .status(exceptions.BAD_REQUEST_EXCEPTION)
      .json({ error: responseMessages.ENTER_VALIDE_CREDENTIALS });
  }

  if (!user.isActive) {
    return res
      .status(exceptions.FORBIDDEN_EXCEPTION)
      .json({ error: responseMessages.ACCOUNT_IS_INACTIVE });
  }

  const token = jwt.sign({ _id: user.id, _role: user.role }, process.env.JWT_SECRET, {
    algorithm: 'HS256',
    allowInsecureKeySizes: true,
    expiresIn: '24h',
  });

  const cookieOptions = {
        expires: new Date(Date.now() + 86400000),
    secure: true,
    httpOnly: true,
    sameSite: 'Strict', // Adjust based on your requirements
    path: '/dashboard',
  };

    const serialized = serialize( USER_AUTH_TOKEN, token, cookieOptions )
    // req.cookies.set('auth-user', serializedUserData)
  const data = {
    userName: user.name,
  };
    
  
    res.setHeader("Set-Cookie", serialized)
  res.status(exceptions.OK).json({
        data: data
    });
};

export default handler;
updated middleware code @Arinji
import { NextResponse } from 'next/server';
import { jwtDecode } from 'jwt-decode';

export default function middleware(req) {
  const authToken =  req.cookies.get('auth_token');
  const url =  req.nextUrl.clone();
  const url2 =  JSON.stringify(url);

  console.log('request', req.nextUrl.pathname)
  const decodedUser = authToken && jwtDecode(authToken.value)
  console.log('decoded', decodedUser)
  
  //access users list page only if user role is admin
  if (authToken && decodedUser?._role !== 'ADMIN' && url2.includes('/dashboard/pdftoolsdashboard/users')) {
    url.pathname = '/dashboard/pdftoolsdashboard';
    return NextResponse.redirect(url);
  }

  //if user not authenticated, redirect to login page
  if (!authToken && url2.includes('/dashboard/pdftoolsdashboard')) {
    url.pathname = '/dashboard/login'
    return NextResponse.redirect(url)
  }

  //if user successfully authenticated, redirect to dashboard
  if (authToken && decodedUser._role && url2.includes('/dashboard/login')) {
    console.log('authenticated')
    url.pathname = '/dashboard/pdftoolsdashboard'
    return NextResponse.redirect(url)
  }
}

export const config = {
  matcher: ['/dashboard/pdftoolsdashboard/:path*', '/dashboard/:path*'],
}
Morelet’s CrocodileOP
@Arinji i am not using NextJsAuth for this. Whenever i'm done login and its time to redirect, middleware is very fast and don't see the cookie on the first request. I'm thinking of using zustand persist to store cookies on login. How does that sound?