skip to Main Content

What I want to achieve here is, whenever a user logs in, I want to store the data returned because the data holds an ID that I would use to fetch data in other routes.
When a user successfully logs in, he would be redirected to the /home route and the ID gotten from the session would be used to fetch data. Everything works fine initially, but if I refresh the home page, the user becomes null.

This is what my […nextauth].js looks like.

import NextAuth from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";
import axios from "axios";

export default NextAuth({
  providers: [
    CredentialsProvider({
      name: "credentials",

      credentials: {
        username: { label: "Username", type: "text", placeholder: "justin" },
        password: {label: "Password",type: "password",placeholder: "******"},
      },

      async authorize(credentials, req) {
        const url = req.body.callbackUrl.split("/auth")[0];
        const { username, password } = credentials;
        const user = await axios({
          url: `${url}/api/user/login`,
          method: "POST",
          data: {
            username: username,
            password: password,
          },
          "content-type": "application/json",
        })
          .then((res) => {
            return res.data;
          })
          .catch((err) => {
            if (err.response.data) {
              throw new Error(err.response.data);
            } else {
              return null;
            }
            return null;
          });
        return user;
      },
    }),
  ],

  callbacks: {
    jwt: ({ token, user }) => {
      if (user) {
        token.user = user;
      }

      return token;
    },
    session: ({ session, token }) => {
      if (token) {
        session.user = token.user;
      }

      return session;
    },
  },

  pages: {
    signIn: "/auth/login",
    newUser: "/auth/register",
  },
});

and this is what my /home route looks like

import Card from "@/components/card/Card";
import React, { useEffect, useState } from "react";
import styles from "./home.module.css";
import { Ubuntu } from "@next/font/google";
import { useSession } from "next-auth/react";
import { useDispatch, useSelector } from "react-redux";

const ubuntu = Ubuntu({ weight: "500", subsets: ["cyrillic"] });
const getData = async (id) => {
  const res = await fetch({
    url: "http://localhost:3000/api/note/getall",
    method: "POST",
    "content-type": "application/json",
    data: {
      id: id,
    },
  });
  if (!res.ok) {
    console.log(id);
    throw new Error("Unable  to fetch");
  } else {
    return res.json();
    console.log(res);
  }
};

function home() {
  const colors = ["#E9F5FC", "#FFF5E1", "#FFE9F3", "#F3F5F7"];
  const random = Math.floor(Math.random() * 5);
  const rc = colors[random];
  const [pop, setPop] = useState("none");
  const { user } = useSelector((state) => state.user);
  const getDataa = async () => {
    console.log(user)
    const data = await getData(user._id);
    console.log(data);
  };
  useEffect(() => {
    if (user) {
      alert(user)
    }
  }, []);
  return (
    <div className={styles.home}>
      <header>
        <h3 className={ubuntu.className}>
          Hello, <br /> {user?.username}!
        </h3>
        <input type="text" placeholder="search" />
      </header>

      <div className={styles.nav}>
        <h1 className={ubuntu.className}>Notes</h1>
      </div>

      <div className={styles.section}>
        <div className={styles.inner}>
          {/*           {data &&
            data.map((e) => (
              <Card
                rawData={e}
                color={colors[Math.floor(Math.random() * colors.length)]}
              />
            ))} */}
        </div>
      </div>

      <div className="new"></div>
    </div>
  );
}

export default home;

2

Answers


  1. Add this component to your App.js file :

    function Auth({ children }) {
      const router = useRouter();
      const { status } = useSession({
        required: true,
        onUnauthenticated() {
          router.push("/sign-in");
        },
      });
    
      if (status === "loading") {
        return <div>Loading ...</div>;
      }
      return children;
    }
    

    Now in your App function instead of returning <Component {...pageProps} /> you check first if the component has auth property, so you wrapp it with <Auth> to ensure that every component that requires session will only mount when the session finishes loading (that’s why the user is null because the session is still loading)

    {
      Component.auth ? (
        <Auth>
          <Component {...pageProps} />
        </Auth>
      ) : (
        <Component {...pageProps} />
      );
    }
    
    

    finally you add .auth = {} to every page in whitch you want the session to be defined (Home in your case)

    const Home = () => {
    //....
    }
    Home.auth = {};
    

    This also helps to redirect user to /sign-in page if the session is expired

    Login or Signup to reply.
  2. This code seems like it would create a problem / race-condition since you’re mixing two different async promise handling styles:

    const user = await axios({
      url: `${url}/api/user/login`,
      method: "POST",
      data: {
        username: username,
        password: password,
      },
      "content-type": "application/json",
    })
      .then((res) => {
        return res.data;
      })
      .catch((err) => {
        if (err.response.data) {
          throw new Error(err.response.data);
        } else {
          return null;
        }
        return null;
      });
    return user;
    

    It should either be this:

    try {
      const user = await axios({
        url: `${url}/api/user/login`,
        method: "POST",
        data: {
          username: username,
          password: password,
        },
        "content-type": "application/json",
      });
      return user.data;
    } catch (err) {
      if (err.response.data) {
        throw new Error(err.response.data);
      } else {
        return null;
      }
    }
    

    Or this:

    axios({
      url: `${url}/api/user/login`,
      method: "POST",
      data: {
        username: username,
        password: password,
      },
      "content-type": "application/json",
    }).then((res) => {
      return res.data;
    }).catch((err) => {
      if (err.response.data) {
        throw new Error(err.response.data);
      } else {
        return null;
      }
      return null;
    });
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search