Every time I refresh the page, the user is automatically logged out

I am currently working on developing an admin dashboard using nextjs 13. I have encountered a specific issue where the user is redirected to the login page every time they reload the page. Upon inspecting in developer mode, I noticed that cookies are still present in the Cookies section, but both Session Storage and Local Storage appear empty, and the token changes with each login attempt. At this point, I have not yet implemented any middleware.

api/auth/[...nextauth]/route.js

import {authOptions} from '@/lib/auth'
import NextAuth from 'next-auth/next'

const handler = NextAuth(authOptions)

export {handler as GET, handler as POST}

/lib/auth.js

import { NextAuthOptions } from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";
import { PrismaAdapter } from "@next-auth/prisma-adapter";
import { db } from "./db";
import { compare } from "bcryptjs";

export const authOptions = {
  adapter: PrismaAdapter(db),
  secret: process.env.NEXTAUTH_SECRET,
  session: {
    strategy: "jwt",
    maxAge: 60 * 60 * 24 * 30,
  },
  pages: {
    signIn: "/sign-in",
  },
  rememberMe: {
    label: "Remember Me",
    type: "checkbox",
  },
  providers: [
    CredentialsProvider({
      name: "Credentials",
      credentials: {
        email: {
          label: "Email",
          type: "email",
          placeholder: "<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="27433e51424967404a464e4b0944484a">[email protected]</a>",
          validation: {
            required: true,
            pattern:
              /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/,
          },
        },
        password: { label: "Password", type: "password", placeholder: "****" },
      },
      async authorize(credentials) {
        if (!credentials?.email || !credentials?.password) {
          return null;
        }

        const existingUser = await db.user.findUnique({
          where: { email: credentials?.email },
        });

        if (
          (existingUser &&
            existingUser.passwordExpirationDate &&
            existingUser.passwordExpirationDate < new Date()) ||
          (existingUser &&
            existingUser.verificationCodeExpiresAt &&
            existingUser.verificationCodeExpiresAt < new Date())
        ) {
          return null; // Trigger password reset
        }

        if (!existingUser) {
          return null;
        }
        const passwordMatch = await compare(
          credentials.password,
          existingUser.password
        );
        if (!passwordMatch) {
          return null;
        }

        const passwordAgeInDays = existingUser.lastPasswordResetDate
          ? Math.floor(
              (new Date().getTime() -
                existingUser.lastPasswordResetDate.getTime()) /
                (1000 * 60 * 60 * 24)
            )
          : 0;

        if (passwordAgeInDays > 30) {
          await db.user.update({
            where: { id: existingUser.id },
            data: { IsExpired: true },
          });
          return null;
        }
        const maxAge = credentials.rememberMe ? 60 * 60 * 24 * 30 : 60 * 60 * 24;
        return {
          id: `${existingUser.id}`,
          name: existingUser.name,
          username: existingUser.username,
          email: existingUser.email,
          role: existingUser.role,
          exp: Math.floor(Date.now() / 1000) + maxAge,
        };
      },
    }),
  ],
  callbacks: {
    async jwt({ token, user }) {

      if (user) {
        return {
          ...token,
          id: user.id,
          username: user.username,
          role: user.role,
        };
      }
      return token;
    },
    async session({ session, token }) {
      const maxAge = token.exp - Math.floor(Date.now() / 1000);
      return {
        ...session,
        user: {
          ...session.user,
          id: token.id,
          username: token.username,
          role: token.role,
        },
        expires: Math.floor(Date.now() / 1000) + maxAge,
      };
    },
  },
};

The main goal is to maintain the user's logged-in status and effectively manage their session.

Answer №1

It's important to consider how the session is managed and validated in your Next.js application with NextAuth. Before diving into code, make sure to check a couple of crucial details:

a) Confirm that your current configuration specifies JWT for session management. Double-check that your .env file contains the NEXTAUTH_SECRET.

NEXTAUTH_SECRET=your_super_secret_value

b) Verify that the client's clock is synchronized with the server's clock to avoid potential token expiration issues due to time discrepancies.

If everything checks out, you can implement a middleware in Next.js to validate sessions and prevent users from being redirected to the login page upon refresh. Create a file named _middleware.js in your pages directory and insert the following code. This middleware ensures user authentication before rendering any page and redirects to the login page if needed.

import { getToken } from "next-auth/jwt";

const secret = process.env.NEXTAUTH_SECRET;

export async function middleware(req) {
    const token = await getToken({ req, secret });

    const { pathname } = req.nextUrl;

    // Authorize requests under specific conditions...
    // 1. Requests related to next-auth session & provider fetching
    // 2. Token existence
    if (pathname.includes('/api/auth') || token) {
        return NextResponse.next();
    }

    // Redirect to login if not authenticated
    if (!token && pathname !== '/login') {
        const url = req.nextUrl.clone();
        url.pathname = '/login';
        return NextResponse.redirect(url);
    }
}

Additionally, ensure proper handling of session status changes on the client side. Utilize the useSession hook from next-auth/react to manage session states effectively. Here's an example:

import { useSession, signIn, signOut } from "next-auth/react";

const MyComponent = () => {
    const { data: session, status } = useSession({
        required: true,
        onUnauthenticated() {
            // User is unauthenticated, redirect to login page
            signIn();
        }
    });

    if (status === "loading") {
        return <p>Loading...</p>;
    }

    return <p>Welcome {session.user.email}</p>;
};

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Initiate a new TypeScript project using Create-Next-App

Currently, I'm attempting to create a new nextJs project using javascript. However, whenever I execute the following command npx create-next-app -e with-tailwindcss ./, it ends up generating a typescript project instead. If anyone could provide assis ...

Tips for utilizing Variant on an overridden component using as props in ChakraUI

I created a custom Component that can be re-rendered as another component using the BoxProps: export function Label ({ children, ...boxProps }: BoxProps) { return ( <Box {...boxProps}> {children} </Box> ); } It functio ...

Geocomplete Plugin without Google Branding

I've implemented the jQuery Geocomplete Library. This is what I have accomplished so far- $(function() { $("#find_product_location").geocomplete( { map: "#product_location", mapOptions: { mapTypeId : 'roadmap',//roadmap, satellite,hybrid ...

Is there a new update to Google Maps API?

After successfully building a map component for a web application using google maps, open layers, and the dojo toolkit, it suddenly stopped loading earlier this morning. Even though there are no JavaScript errors and open layers and Google still initialize ...

Exploring the usage of slots in WebComponents without relying on shadow DOM

I am working on developing a WebComponent without utilizing ShadowDOM. So far, everything has been going smoothly. However, I now aim to create a component that wraps other components similar to how it is done in Angular with @ViewChild / @ViewChildren. (I ...

If you include react-multi-date-picker with the render prop set to <InputIcon />, it may trigger a warning in

https://i.sstatic.net/9hOe4.png Looks like the code is missing a function with that name. I followed the documentation and added the icon, but ended up receiving a warning. In next-dev.js:20 Warning: React is not recognizing the handleValueChange prop o ...

What is the best way to pass environment variables in Vercel for applications outside of Next.js?

After deploying a standard React application to Vercel, I am interested in setting up an API_BASE_URL environment variable with different values for the development, preview, and production environments. Normally, I would utilize the dotenv npm package al ...

How to disable a specific array of dates in Ant Design range picker

Is there a way to block dates prior to the current date and specify certain dates that should also be disabled on the calendar? For example, I need to prevent selection of: Today: 2018-07-30 Dates to disable: [2018-08-10, 2018-08-12, 2018-08-20] When t ...

Executing a function after the completion of another

Here is my function: function functionName($results) { //do some stuff disableSave() } When this function runs, I want to call the enableSave() function. How can I achieve this? I attempted to pass the function as a callback but I am unsure wher ...

The websocket server implemented in Node.js with the use of the "ws" library is exhibiting a peculiar behavior where it disconnects clients at random intervals,

My WebSocket server implementation is quite simple: const WebSocket = require('ws'); const wss = new WebSocket.Server( { server: server, path: "/ws" }); wss.on('connection', function connection(ws, req) { console.log("Connect ...

What is the process for including a new item in an array of objects?

const data = [ { title: 'Tasks', items: ['complete assignments', 'study for exams'], }, { title: 'Ongoing', items: ['learn new skills', 'work on projects'], }, { titl ...

Retrieve the variable from a function that is invoking the export.modules in node.js

How can I extract the code from the randomCode() function in the users.js file, assign it to the result variable, and use it throughout the entire '/login' endpoint? randomCode.js const crypto = require('crypto') const randomCode = (c ...

Utilizing ng-repeat, ng-grid, and ng-click in Angular: A comprehensive guide

I'm encountering an issue with populating a table using ng-repeat after a cellTemplate ng-click. cellTemplate: '<div ng-click="foo()" ng-bind="row.getProperty(col.field)"></div>' Within this foo method, I am tryi ...

How to Embed a Javascript (jquery) Variable within a JSON Object

I have searched everywhere for a "simple answer" to this problem, but unfortunately, I cannot find a solution that aligns with my understanding of JSON and jQuery. Perhaps I am too much of a beginner in JSON to accurately formulate the right question (and ...

Exploring JavaScript and accessing objects

I'm currently working on a small file-manager project in JavaScript and I've encountered an issue with the code. In the `get()` function, I am trying to access the `Content.files` array but it seems like there's some problem with variable sc ...

Stop aspx button postback on click using cSharp

The following HTML code snippet includes an <asp:Button> element. <asp:Button ID="CalculateG481" runat="server" Text="Calculate" OnClick="CalculateG481_Click" /> When clicked, the button calls the function CalculateG481_Click but then initia ...

RecoilRoot from RecoilJS cannot be accessed within a ThreeJS Canvas

Looking for some guidance here. I'm relatively new to RecoilJS so if I'm overlooking something obvious, please point it out. I'm currently working on managing the state of 3D objects in a scene using RecoilJS Atoms. I have an atom set up to ...

Preserving Foreign Key Relationships in Django Rest Framework Serializers

Within my project, I have two interconnected models named Task and Batch, linked through a Foreign Key field. My goal is to verify the existence of a Batch Object in the database before creating a new Task Object. The Batch object represents the current da ...

Retrieve the loading status of a manually triggered RTK Query mutation

I'm currently developing a Next.js project utilizing RTK Query. I am seeking guidance on how to access the isLoading state of a mutation that is triggered in a specific way (refer to: https://redux-toolkit.js.org/rtk-query/api/created-api/endpoints#in ...

"Strategically placing elements on an HTML grid

My current project involves creating a grid layout in HTML using CSS. The goal is to use this layout for various elements such as images, text, and links. What I envision is a visually appealing grid where each object fits together seamlessly with no gaps ...