Reputation: 1
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
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
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