Milan Poudel
Milan Poudel

Reputation: 792

Axios error 401 message pops up in app before trying refresh token in axios interceptor

AxiosConfig.js


import axios from "axios";
import { store } from "./redux/store";
import { login, logout } from "./redux/slices/user";

const baseURL = process.env.NEXT_PUBLIC_API_URL;

axios.defaults.baseURL = baseURL;

export const axiosInstance = axios.create({
  withCredentials: true,
  headers: {
    "Content-Type": "application/json",
    "Access-Control-Allow-Origin": "*",
    accept: "application/json",
  },
});

axiosInstance.interceptors.request.use(
  (config) => {
    return config;
  },
  (error) => {
    return Promise.reject(error);
  }
);

axiosInstance.interceptors.response.use(
  (response) => {
    return response;
  },
  async (error) => {
    const originalRequest = error?.config;
    if (error?.response?.status === 401 && !originalRequest.sent) {
      originalRequest.sent = true;
      const response = await axios.get("/auth/refresh", {
        withCredentials: true,
      });
      if (response.error.status === 403) {
        store.dispatch(logout());
      }
      store.dispatch(login({ user: response.data.user }));
      return axiosInstance(originalRequest);
    }
    return Promise.reject(error);
  }
);

VerifyJwt.js

export const verifyToken = (req, res, next) => {
  try {
    const accessToken = req.cookies.accessToken;
    if (!accessToken)
      return res.status(403).json({
        message: "Not authenticated, no token provided",
      });
    jwt.verify(accessToken, process.env.ACCESS_SECRET_KEY, (err, decoded) => {
      if (err)
        return res.status(401).json({
          message: "Not logged in, invalid token",
        });
      req.user = decoded.id;
      next();
    });
  } catch (e) {
    res
      .status(500)
      .json({ message: "Something went wrong while verifying jwt" });
  }
};

routes/video.js

import express from "express";
import { unAuthVerify, verifyToken } from "../middlewares/verifyJwt.js";
import {
  deleteVideo,
  dislikeVideo,
  getVideoDetails,
  getVideos,
  likeVideo,
  updateVideo,
  uploadVideo,
} from "../controllers/videos.js";

const router = express.Router();
router.get("/", getVideos);
router.post("/", verifyToken, uploadVideo);
router.get("/:id", unAuthVerify, getVideoDetails);
router.put("/:id", verifyToken, updateVideo);
router.delete("/:id", verifyToken, deleteVideo);
router.put("/like/:id", verifyToken, likeVideo);
router.put("/dislike/:id", verifyToken, dislikeVideo);

export default router;

RefreshToken.js

export const refreshToken = async (req, res) => {
  const refreshToken = req.cookies.refreshToken;
  try {
    if (refreshToken) {
      jwt.verify(
        refreshToken,
        process.env.REFRESH_SECRET_KEY,
        async (err, decoded) => {
          if (err) {
            return res.status(403).json({
              message: "Invalid token/not logged in",
            });
          }
          const accessToken = jwt.sign(
            { id: decoded.id },
            process.env.ACCESS_SECRET_KEY,
            {
              expiresIn: "1m",
            }
          );
          const foundUser = await db.query(
            "SELECT * FROM channels WHERE id = $1",
            [decoded.id]
          );
          if (foundUser.rows.length <= 0) {
            return res.status(400).json({
              message: "User/Channel not found",
            });
          }
          const { password, ...others } = foundUser.rows[0];
          if (foundUser.rows.length > 0) {
            res.cookie("accessToken", accessToken, {
              httpOnly: true,
              secure: true,
            });
            return res.status(200).json({
              user: others,
            });
          }
        }
      );
    } else {
      return res.status(403).json({
        message: "Invalid token/not logged in",
      });
    }
  } catch (e) {
    console.log(e);
    res.status(500).json({
      message: "Something went wrong.Please try again",
    });
  }
};

Video.jsx

const handleLike = async (id) => {
   if (!isLoggedIn) {
     toast.error("You need to login to like a video");
     return;
   }
   if (likedByMe) {
     toast.success("You have already liked this video");
     return;
   }

   try {
     await axiosInstance.put(`/videos/like/${id}`);
     setLikes((prev) => prev + 1);
     if (likedByMe === false) {
       setDisLikes((prev) => prev - 1);
     }
     setLikedByMe(true);
   } catch (e) {
     console.log("Something went wrong while liking video", e);
     toast.error(e.response.data.message);  //I am getting this error first and the app is 
   crashing and only then axios interceptors call refresh token endpoint)
   }
 };

I am trying to refresh token in axios interceptor and get new access token. For example, if suppose I try to dislike or like any video and my access token expires at that time, I will get 401 message that token has expired, but I thought before getting this response in client side that is happening inside catch block, axios interceptor will call refresh token since it is 404 message and the client will get new access token and then the dislike or like api request will happen again. But in my app, I am getting that error message and it's crashing the app, shouldn't axios interceptor handle it silently? That 404 aunthorized message is getting catched by catch block in client side and errors pops up

enter image description here

Upvotes: 0

Views: 912

Answers (1)

Lazar Nikolov
Lazar Nikolov

Reputation: 1028

I can notice that your route is named video.js but you're sending a PUT request to videos/ (plural). Is that a typo, or that's the cause of your issue?

Upvotes: 1

Related Questions