Amarentix
Amarentix

Reputation: 1

Axios (React) + Express: 401 Unauthorized error when sending JWT in Authorization header

I’m working on a MERN stack application (MongoDB, Express, React, Node.js). On the frontend, I use Axios for HTTP requests. The issue arises when I try to send a JWT in the Authorization header — the server responds with a 401 Unauthorized error.

Here’s what I’ve done so far:

I retrieve the token from localStorage on the frontend. I send the token in the Authorization header in the format Bearer <token>. The backend uses jsonwebtoken to verify the token. Despite these steps, the server rejects the request. I’d appreciate help identifying the issue.

Frontend Code:

import React, { useEffect } from "react";
import axios from "axios";

const ShowDish = () => {
  useEffect(() => {
    const fetchDishes = async () => {
      try {
        const token = localStorage.getItem("token");
        if (!token) {
          throw new Error("Token is missing! Please log in again.");
        }

        const response = await axios.get("http://localhost:5000/api/dishes", {
          headers: {
            Authorization: `Bearer ${token}`,
          },
        });
    
        console.log("Dishes:", response.data);
      } catch (error) {
        console.error("Error fetching dishes:", error);
      }
    };  
    fetchDishes();
  }, []);

  return <div>Loading dishes...</div>;
};

export default ShowDish;

Backend Code:

const jwt = require("jsonwebtoken");
const express = require("express");
const app = express();

const JWT_SECRET = "supersecretkey"; // (Store this in a .env file)

app.use(express.json());

// Generate token during login
app.post("/api/login", (req, res) => {
  const { email, password } = req.body;

  // Example user (in a real app, validate against the database)
  const user = { id: "123", email, role: "user" };

  const token = jwt.sign(
    { id: user.id, email: user.email, role: user.role },
    JWT_SECRET,
    { expiresIn: "1h" }
  );

  res.json({ token });
});

Middleware


const jwt = require("jsonwebtoken");

const verifyToken = (req, res, next) => {
  const token = req.cookies.token;

  if (!token) {
    return res.status(401).json({ message: "Not authenticated" });
  }

  try {
    const decoded = jwt.verify(token, process.env.JWT_SECRET);
    req.user = decoded; 
    next();
  } catch (err) {
    return res.status(403).json({ message: "Invalid token" });
  }
};

const authenticateToken = (req, res, next) => {
  const authHeader = req.headers["authorization"];
  const token = authHeader && authHeader.split(" ")[1]; 
  if (!token) {
    return res.status(401).json({ message: "Token is missing" });
  }

  jwt.verify(token, process.env.JWT_SECRET, (err, user) => {
    if (err) {
      return res.status(403).json({ message: "Invalid token" });
    }
    req.user = user;
    next();
  });
};

Protected endpoint:

app.get("/api/dishes", verifyToken , (req, res) => {
  res.json({ message: "Here are the dishes!", user: req.user });
});

const PORT = 5000;
app.listen(PORT, () => console.log(Server is running on port ${PORT}));

Expected Behavior:

When sending a GET request to http://localhost:5000/api/dishes with a valid token in the Authorization header, I expect to receive a response with data (e.g., the list of dishes).

Actual Behavior:

AxiosError: Request failed with status code 401

What I’ve tried: Verified the token is correct by decoding it on jwt.io. Confirmed the token is being sent in the Authorization header as Bearer <token>. Double-checked the backend middleware for verifying the token. What could be causing this issue? Thank you for any guidance! And I apologize for my bad English, I have to use translator

Upvotes: 0

Views: 47

Answers (2)

XH栩恒
XH栩恒

Reputation: 505

You are passing the token in the header from the frontend, so you should retrieve them from the header as well from the backend instead of cookies

On your "/api/dishes" route, you are using verifyToken method to verify the token from request cookies instead of header.

You should replace the verifyToken method on the "/api/dishes" route with authenticateToken

Upvotes: 0

ympek
ympek

Reputation: 351

It seems like you are first trying to retrieve the token from cookies, and you return 401 if it's not there:

const token = req.cookies.token;

if (!token) {
return res.status(401).json({ message: "Not authenticated" });
}

Maybe you should not end the middleware code here, but instead let it pass and check the headers, like you are doing below.

Upvotes: 1

Related Questions