I am using JWT to set a token for user authentication on specific routes. The authentication works perfectly with the Postman routes, but when I log in using the browser and the app sends the GET requests to my Heroku backend, I get a 401 Unauthorized error. I am using the same Heroku URL when sending a postman request, so I am sure that my Heroku hosting is not the issue.
The flow of the app is as follows:
Once a user tries to log in, we check credentials with the DB and if the credentials are correct, we then assign a jwt token to the cookie. This occurs on the server side using the encode function below.
export const encode = async (req, res, next) => {
try {
const { username, password } = req.params;
const verifiedLogin = await User.onUserLogin(username, password);
if (verifiedLogin.success === false) {
return res.status(401).json({ success: false, message: "Invalid login credentials" });
}
const token = jwt.sign({ userid: verifiedLogin.user._id, userType: verifiedLogin.user.type }, SECRET_KEY);
res.cookie("Authorization", token, { httpOnly: false, secure: false });
console.log("cookie", res.cookie);
return res.status(200).json({ success: true, userId: verifiedLogin.user._id });
} catch (error) {
return res.status(400).json({
success: false,
message: "Problem while trying to authenticate ",
error: error,
});
}
};
Once the user is logged in, we then run a series of GET requests from the client side to retrieve some data from our DB. None of the GET requests are authorized after login so I will only provide one of them here.
export const fetchUserGroups = async () => {
let roomsFromResponse = [];
// Request to get the groups the user is part of for the groups panel
await axios
.get(`http://saldanaj97-chattyio.herokuapp.com/room/user-messages/`, CONFIG)
.then((response) => {
response.data.roomIds.map((room) => {
const newRoom = { id: room._id, groupName: room.groupName, lastMessageReceived: { user: "", contents: "" } };
return (roomsFromResponse = [newRoom, ...roomsFromResponse]);
});
})
.catch((error) => {
console.log("Auth error when retrieving users groups", error);
});
return roomsFromResponse;
};
Lastly, when a user is trying to access a route that requires authentication(such as the one above), the decode middleware below is used to decode the jwt token.
export const decode = (req, res, next) => {
if (req.cookies === "") {
return res.status(400).json({ success: false, error: "No access token provided " });
}
const accessToken = req.cookies["Authorization"];
try {
const decoded = jwt.verify(accessToken, SECRET_KEY);
req.userId = decoded.userid;
req.userType = decoded.userType;
return next();
} catch (error) {
return res.status(401).json({
success: false,
message: "Could not decode authorization token",
});
}
};
Below are my cors settings from the backend.
// Cors
const corsOptions = {
origin: ["http://localhost:3000"],
exposedHeaders: ["Authorization"],
};
app.use(cors(corsOptions));
app.use((req, res, next) => {
res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content, Accept, Content-Type, Authorization");
res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS");
res.setHeader("Access-Control-Allow-Credentials", true);
next();
});
When a user logs in, an error is caught and the error is posted in the console with a 401 code along with the 'could not decode authorization token' from the decode function catch block from above. When I go to check the application settings in chrome, there is no Authorization token being set after login, but when I run the same GET request in postman, the cookies ARE being set.
I have tried different things such as settings 'httpOnly' to true as well as setting 'secure' to true but neither has worked. This is my first app that I have tried hosting and every feature was working fine while developing in localhost but once I put it on Heroku I have not been able to get the authorization to work in the browser even though all my requests from postman continue working.
I am not sure if this is a cors issue, an issue with the decode function, or a different issue altogether. Any help would be appreciated.
CodePudding user response:
If you're not on the same domain, you can't set cookie for the client from server, it works in postman since you're hitting the endpoint from the same domain.