When checking the cookie I get an undefined - reactjs

everyone. I'm trying to set a cookie using epress for 24 hours. Setting also works (developer tools). For example, if I now go into standby mode and return to the application, click on something that triggers a request 'load all articles of a user', then the token is undefinded and the cookie is said to be not set. How can I fix this?
In Debugger I see the access_token cookie. So this is there, but when I check 'verifyToken.js' I get an undefined.
ladeAlleArtikelEinesUsers:
const ladeAlleArtikelEinesUsers = async (artikelId) => {
try {
await axiosInstance
.post(`/artikel/finde/${artikelId}`, { withCredentials: true })
.then(async (res) => {
//TOKEN is undefined here
if (res.data.error) {
signOut(auth)
.then(() => {
dispatch(logout());
navigate("/Login");
})
.catch((error) => {
console.log(error);
});
} else {
setArtikelEinesUsers(res.data);
setOeffneArtikelEinesUsersDialog(true);
}
});
} catch (error) {
console.log(error);
}
};
verifyToken.js
export const verifyToken = (req, res, next) => {
const token = req.cookies.access_token;
console.log("TOKEN: " + token ); //UNDEFINED
if (!token) {
return res.status(200).send({
error: true,
msg: "Authentication Failed.",
});
}
jwt.verify(token, process.env.JWT, (err, user) => {
if (err) {
return res.status(200).send({
error: true,
msg: "Authentication Failed.",
});
}
req.user = user;
next();
});
};
route
router.post("/finde/:id", verifyToken, EinArtikel);

Related

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
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?

Unable to verify user token stored in cookie in MERN app

I am trying to verify a logged In user token in my MERN. However, I am getting "undefined" on client-side as API response.
When I hit the endpoint http://127.0.0.1:1000/api/v1/users/login in postman to login a user and this endpoint http://127.0.0.1:1000/api/v1/users/verify to verify a user's token, the token is returned.
But when I do the same in my react app, the token returns undefined. I have spent hours debugging it but unable to figure it out.
Please I need help.
Here is my React (client side) code:
axios.defaults.withCredentials = true;
function Welcome() {
const [user, setUser] = useState("");
const sendRequest = async () => {
const res = await axios
.get("http://127.0.0.1:1000/api/v1/users/verify", {
withCredentials: true,
})
.catch((err) => console.log(err));
const data = await res.data;
return data;
};
React.useEffect(() => {
sendRequest().then((response) => console.log(response.data));
}, []);
return <div>Welcome</div>;
}
Here is my login endpoint.
exports.loginUser = async (req, res) => {
const { name, password } = req.body;
let existingUser;
try {
existingUser = await User.findOne({ name: name });
} catch (err) {
return new Error(err);
}
if (!existingUser) {
return res.status(400).json({ status: "fail", message: "user not found" });
}
const isPasswordCorrect = bcrypt.compareSync(password, existingUser.password);
if (!isPasswordCorrect) {
return res
.status(400)
.json({ status: "fail", message: "invalid email or password" });
}
const token = jwt.sign({ id: existingUser._id }, process.env.JWT_SECRET, {
expiresIn: process.env.JWT_EXPIRES_IN,
});
res.cookie("jwt", token, {
path: "/",
expires: new Date(Date.now() + 1000 * 70),
httpOnly: true,
sameSite: "lax",
});
return res
.status(200)
.json({ message: "Succesfully loggedIn", user: existingUser, token });
};
Here is my verifyToken endpoint
exports.verifyToken = (req, res, next) => {
const cookies = req.headers.cookie;
const token = cookies.split("=")[1];
if (!token) {
res.status(404).json({ message: "no token found" });
}
jwt.verify(String(token), process.env.JWT_SECRET, (err, user) => {
if (err) {
return res.status(400).json({ message: "Invalid token" });
}
req.id = user.id;
});
next();
};
router.route("/verify").get(verifyToken, getUser);//endpoint
exports.getUser = async (req, res, next) => {
const userId = req.id;
let user;
try {
user = await User.findById(userId, "-password");
} catch (err) {
return new Error(err);
}
if (!user) {
return res.status(404).json({ status: "fail", message: "user not found" });
}
return res.status(200).json({ user });
};

Token undefined in put and patch request. MERN stack application

Working with a mern application. I am passing token in authorization header. The issue is whenever I use put or patch method from frontend, token is undefined. Get, Post, Delete requests are working fine. Api is working fine with postman too.
frontend action ->
export const approveClient = (id) => async (dispatch) => {
try {
const config = {
headers: {
Authorization: `${localStorage.getItem("token")}`,
},
};
dispatch({ type: adminConstants.APPROVECLIENT_REQUEST });
const res = await axios.put(`/admin/approveClient/${id}`, config);
dispatch({
type: adminConstants.APPROVECLIENT_SUCCESS,
payload: res.data,
});
} catch (error) {
dispatch({
type: adminConstants.APPROVECLIENT_FAIL,
payload: error.response.data,
});
}
};
Backend middleware function ->
const isAuthenticated = async (req, res, next) => {
try {
const token = req.headers.authorization;
if (!token) {
return res.status(401).json({ success: false, message: "Not logged in" });
}
const decoded = jwt.verify(token, process.env.JWT_SECRET);
const user = await User.findById(decoded._id);
const client = await Client.findById(decoded._id);
const admin = await Admin.findById(decoded._id);
if (user) {
req.user = user;
}
if (client) {
req.user = client;
}
if (admin) {
req.user = admin;
}
next();
} catch (error) {
res.status(500).json({ success: false, message: error.message });
}
};

PassportJS Express req.user not persisting in Heroku

I am using React and Express. Only the React is hosted on heroku and I am hosting the Express server locally. With Express I am using Passportjs with MongoDB.
The problem is that React clien t works well on local deployment, however once I deploy my React App on Heroku it does not work well propertly. When using my deployed React app, I can register a user but I cannot log in a user. It does not return error and POST("/login") returns "Successfully Authenticated" back to me and when I try to access req.user using axios it returns nothing back when it should be returning the user.
React Code
const getUser = () => {
axios({
method: "GET",
withCredentials: true,
url: "http://localhost:3001/user",
})
.then((res) => {
{
console.log(res.data);
if (res.data.username != null)
setMessage("Welcome " + res.data.username);
}
})
.catch((err) => console.log(err));
};
const loginTheUser = async () => {
await axios({
method: "POST",
data: {
username: username,
password: password,
},
withCredentials: true,
url: "http://localhost:3001/login",
}).then((res) => {
if (res.data === "Successfully Authenticated") {
history.push("/");
}
console.log(res.data);
});
await getUser();
};
Express code
// Middleware
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(
cors({
origin: [
"http://localhost:3000",
"https://my-herokuapp.com",
], // <-- location of the react app were connecting to
credentials: true,
})
);
app.use(
session({
secret: "secretcode",
resave: true,
saveUninitialized: true,
})
);
app.use(cookieParser("secretcode"));
app.use(passport.initialize());
app.use(passport.session());
require("./passportConfig")(passport);
//Login
app.post("/login", (req, res, next) => {
passport.authenticate("local", (err, user, info) => {
if (err) throw err;
if (!user) {
console.log("Unsuccessful login");
res.send("Unsuccessful login");
} else {
req.logIn(user, (err) => {
if (err) throw err;
{
console.log("Login success");
res.send("Successfully Authenticated");
}
});
}
})(req, res, next);
});
//Register
app.post("/register", (req, res) => {
User.findOne({ username: req.body.username }, async (err, doc) => {
if (err) throw err;
if (doc) res.send("User Already Exists");
if (!doc) {
const hashedPassword = await bcrypt.hash(req.body.password, 10);
const newUser = new User({
username: req.body.username,
password: hashedPassword,
});
await newUser.save();
res.send("User Created");
}
});
});
//get User
app.get("/user", (req, res) => {
res.send(req.user); // The req.user stores the entire user that has been authenticated inside of it.
});
Passport config
const User = require("./user");
const bcrypt = require("bcryptjs");
const localStrategy = require("passport-local").Strategy;
module.exports = function (passport) {
passport.use(
new localStrategy((username, password, done) => {
User.findOne({ username: username }, (err, user) => {
if (err) throw err;
if (!user) return done(null, false);
bcrypt.compare(password, user.password, (err, result) => {
if (err) throw err;
if (result === true) {
return done(null, user);
} else {
return done(null, false);
}
});
});
})
);
passport.serializeUser((user, cb) => {
cb(null, user.id);
});
passport.deserializeUser((id, cb) => {
User.findOne({ _id: id }, (err, user) => {
const userInformation = {
username: user.username,
};
cb(err, userInformation);
});
});
};

Returning response from Dispatch

I'm implementing login functionality to my application and am trying to return the response from a dispatched thunk action. I'm purposely entering the incorrect password because i'd like for the errors that are set in my backend to display within an antd notification on the frontend. My expected response should be:
return res.status(400).json({
success: false,
message: 'Invalid email address or password.',
});
but instead i'm getting the following in the console:
Error: Request failed with status code 400
Route:
const loginUser = async (req, res) => {
// Validate Login Input
const { error } = validateLoginInput(req.body);
if (error)
return res
.status(400)
.json({ success: false, message: error.details[0].message });
req.body.email = req.body.email.toLowerCase();
req.body = sanitize(req.body);
const { email, password } = req.body;
try {
// See if user exists
let user = await User.findOne({ email });
if (!user) {
return res.status(400).json({
success: false,
message: 'Invalid email address or password.',
});
}
// Compare passwords
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) {
return res.status(400).json({
success: false,
message: 'Invalid email address or password.',
});
}
// Return jsonwebtoken
const payload = {
user: {
id: user.id,
},
};
jwt.sign(
payload,
process.env.JWT_SECRET,
{ expiresIn: 3600 },
(error, token) => {
if (error) throw error;
res.json({ token });
}
);
} catch (error) {
res.status(500).json({ success: false, messsage: 'Server error' });
}
};
Actions:
export const loginBegin = () => ({
type: LOGIN_BEGIN,
});
export const loginSuccess = (user) => ({
type: LOGIN_SUCCESS,
payload: user,
});
export const loginFail = (error) => ({
type: LOGIN_FAIL,
payload: error,
});
Thunk:
export const attemptLogin = (formData) => async (dispatch) => {
dispatch(loginBegin());
return await postLogin(formData)
.then((res) => {
dispatch(loginSuccess(res.data));
console.log(res.data); <-- This doesn't even show in console
})
// .then(() => {
// setTimeout(() => {
// dispatch(push('/app'));
// }, 2000);
// })
.catch((error) => {
dispatch(loginFail(error));
});
};
onSubmit:
const onSubmit = async (values) => {
const { email, password } = values;
setLoading(true);
try {
const response = await dispatch(attemptLogin({ email, password }));
console.log(response); <-- returns undefined
if (response.data.success) {
setLoading(false);
notification['success']({
message: 'Congrats!',
description: response.message,
});
} else {
notification['error']({
message: 'Uh-oh!',
description: response.message,
});
}
} catch (error) {
console.log(error);
}
};
The problem is that you are not returning the response in the promise. Also, if you are getting a 400 response, it probably rejects the promise or throws an error.
export const attemptLogin = (formData) => async (dispatch) => {
dispatch(loginBegin());
return await postLogin(formData)
.then((res) => {
dispatch(loginSuccess(res.data));
return res;
})
.catch((error) => {
dispatch(loginFail(error));
return error; // this will only work if the error is the response object.
});
};

Resources