This is my Frontend code
const fetchData = () => {
const options = {
method: 'GET',
url: 'http://localhost:1337/user/chart',
headers: {'x-access-token': sessionStorage.getItem('token')},
body: [chartData.datasets]
}
axios.request(options).then((response) => {
console.log(response)
}).catch((error) => {
console.error(error)})
}
This is backend
app.get('/user/chart', async (req, res) => {
const token = req.headers['x-access-token']
if (!token){
return res.status(404).json({ success: false, msg: "Token not found" });
}
try {
const decoded = jwt.verify(token, process.env.access_secret)
const email = decoded.email
await User.updateOne(
{ email: email },
{ $set: {} },
)
console.log(req.body)
return res.status(200).json({message: 'ok', label:[]})
} catch (error) {
console.log(error)
res.json({ status: 'error', error: 'invalid token' })
}
})
When I console.log(req.body) it is an empty {}.
Why is it empty?
I am using a GET request to retrieve the chart data
Axios API does not accept body on get get request you can send parameters with params example
const url = '/user/chart';
const config = {
headers: {'x-access-token': sessionStorage.getItem('token')},
params:{someKey:chartData.datasets}
};
axios.get(url, config)
Axios doesn't support setting a body for a get request, see the docs or this related question.
Though, I'd also recommend to reconsider your design. Typically the body isn't used in a GET request. If you're sending data to the server, you likely want to use POST or PUT instead. If you just want to pass a parameter, then you likely want to use request parameters.
If you absolutely need to send a body in your GET request, then you'll need to use a different tool.
frondend //
const fetchData = () => {
const options = {
method: 'POST',
url: 'http://localhost:1337/user/chart',
headers: {'x-access-token': sessionStorage.getItem('token')},
body: {name : "xx",mail:"xx#"}
}
axios.request(options).then((response) => {
console.log(response)
}).catch((error) => {
console.error(error)})
}
backend //
app.post('/user/chart', async (req, res) => {
const {name , mail} = req.body
const token = req.headers['x-access-token']
if (!token){
return res.status(404).json({ success: false, msg: "Token not found" });
}
try {
const decoded = jwt.verify(token, process.env.access_secret)
const email = decoded.email
await User.updateOne(
{ email: email },
{ $set: {} },
)
console.log(req.body)
return res.status(200).json({message: 'ok', label:[]})
} catch (error) {
console.log(error)
res.json({ status: 'error', error: 'invalid token' })
}
})Ï
Related
I am working on a React and Node app and I don't understand how to pass the error given from the back end to the catch block in the fetch in the front end.
The login function uses fetch that throws an error if the server returns a not-ok status. The server also returns an array of errors that I need to display on the front end.
My problem is that when forcing an error and throwing the error to be caught in the catch block of the fetch promise, I cannot feed the catch with the array of errors returned by the back end.
I feed the response to the catch and there when it is logged it says it is an object Response. And it does not have the errors property coming from the back end response.
This is the login function on the front end:
function handleLogin() {
fetch('http://localhost:5000/auth/login', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({ username, password }),
})
.then((response) => {
if(!response.ok) {
throw Error(response)
}
return response.json()
})
.then((token) => {
localStorage.setItem('token', token);
history.push('/');
window.location.reload();
})
.catch((error) => {
console.log('error: ', error); // error: Error: [object Response]
console.log('error:', error.errors); // undefined
setErrors(error.errors)
})
}
This is the controller of the login in the back end:
exports.login = async (req, res) => {
const { password, username } = req.body;
const hasErrors = validationResult(req);
// VALIDATE INPUTS
if (!hasErrors.isEmpty()) {
console.log('there are errros')
return res.status(401).json({
erros: hasErrors.array(),
});
}
// VALIDATE USER
const user = await User.findOne({ username });
if (!user) {
return res.status(401).send({
erros: [
{
msg: 'Invalid Credentials 1',
},
],
});
}
const isValid = await bcrypt.compare(password, user.password);
if (isValid) {
// SIGN THE JWT
const token = await JWT.sign({ username }, 'mysecret', {
expiresIn: 864_000,
});
return res.json(token);
} else {
return res.status(401).send({
erros: [
{
msg: 'Could not save the user into the db',
},
],
});
}
}
i´m creating a Authentication page with React and Express. I'm using JWT too.
I´ve made this route in the back:
server.js
...
app.use(
cookieSession({
name: "prode_session",
secret: "MIOURI_PRODE_SECRET", //add to .env variable
httpOnly: false,
})
);
app.use(cors());
...
auth.routes.js
app.post("/signin", controller.signin);
user.routes.js
app.get(
"/user",
[authJwt.verifyToken],
(req, res) => res.send(true)
)
auth.controller.js
exports.signin = async (req, res) => {
const user = await Users.findOne({
where: { email: req.body.email },
});
try {
if (!user) {
return res.status(404).send({ message: "User Not found." });
}
const passwordIsValid = bcrypt.compareSync(
req.body.password,
user.password
);
if (!passwordIsValid) {
return res.status(401).send({
message: "Invalid Password!",
});
}
const token = jwt.sign({ id: user.id }, config.secret, {
expiresIn: 84000, //24hours
});
req.session.token = token;
console.log(req.session);
return res.status(200).send({
isLogged: true,
id: user.id,
email: user.email,
suscripcion: user.suscripcion,
preference_id: user.preference_id,
token,
});
} catch (error) {
console.log(error);
}
};
authJWT.js
verifyToken = async (req, res, next) => {
let token = req.session.token;
console.log(`THIS IS THE TOKEN: ${token}`);
if (!token) {
return res.status(403).send({
message: "No token provided",
});
}
jwt.verify(token, config.secret, (err, decoded) => {
if (err) {
console.log(err);
return res.status(401).send({
message: "Unauthorized!",
});
}
req.id = decoded.id;
next();
});
};
const authJwt = { verifyToken };
module.exports = authJwt;
When I test this with POSTMAN, it works Ok, I mean, if first I try to make the GET request, the response is "No token provided", but if I signin first, generate the token and then make the GET request, I get true.
The problem is when I try to implement this in the front.
I have this Login component in React in which I make a POST request with the credentials:
const handleSubmit = async (e) => {
e.preventDefault();
try {
const response = await fetch("http://localhost:3000/signin", {
method: "POST",
mode: "cors",
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
},
body: JSON.stringify({
email,
password,
}),
});
const data = await response.json();
console.log(data);
if (data.isLogged && data.suscripcion === true && data.token) {
await tokenAvailable()
//navigate(`/masthead/${email}&${data.isLogged}&${data.id}`);
} else if (data.isLogged && data.suscripcion === false) {
navigate("/suscripcion", {
state: { preference_id: data.preference_id },
});
} else {
window.alert("Invalid Login");
}
} catch (error) {
console.log(error);
}
};
async function tokenAvailable() {
const user = await fetch("http://localhost:3000/user", {
method: "GET",
mode: "cors",
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
},
});
const response = await user.json();
setUser(await response);
console.log(await response);
return response;
}
When I make the POST, the GET request is executed (tokenAvailable function) after receiving the response, but I receive "No token Provided" while I expect to receive "true" as in Postman.
From what I debug, the authJWT.js file, is not receiving nothing from the req.session.token.
When I compare the headers from postman and the browser, in postan the SET-cookie key appears, but in the browser not.
postman:
browser:
I need some help here. I´ve been strugling with this for almost 3 days.
I found a solution for this. Apparently, the HttpOnly Cookie approach works if the React app and the back-end server hosted in same domain. So we need to use http-proxy-middleware for local development.
I´ve tried to install the http-proxy-middleware but a lot of errors came, so I decided to store de JWT in the localstorage.
I am trying to make sure that the front-end of my app will display the error that I want it to display. I am purposely trying to create a user that already exists and therefore show my custom User already exists. Please log in. error.
It shows in postman when sending a request to the same endpoint, but at the front-end, the response just shows the following and not the actual error message I defined:
Response {type: 'cors', url: 'http://localhost:8000/api/user/create', redirected: false, status: 409, ok: false, …}
body: (...)
bodyUsed: false
headers: Headers {}
ok: false
redirected: false
status: 409
statusText: "Conflict"
type: "cors"
url: "http://localhost:8000/api/user/create"
[[Prototype]]: Response
The createUser controller:
export const createUser = async (req: Request, res: Response) => {
const { email, password } = req.body;
const existingUser = await User.findByEmail(email);
if (existingUser) {
return res.status(409).send('User already exists. Please log in.');
}
const hashedPassword = await bcrypt.hash(password, 10);
const newUser = new User(email, hashedPassword);
const saveToDb = await newUser.saveToDb();
if (!saveToDb) {
return res.status(500).send('Could not insert user into the database.');
}
const token = newUser.signToken();
res.status(201).json({ token, id: saveToDb.insertedId });
};
The front-end submission:
const onSubmit: SubmitHandler<CreateAccountFormInputs> = async (formData) => {
try {
setLoading(true);
const res = await fetch('http://localhost:8000/api/user/create', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(formData),
});
console.log(res); // output shown above
if (!res.ok) {
setError(`HTTP error: ${res.status}`);
return;
}
navigate('/login');
} catch (err: any) {
setError(err.message);
} finally {
setLoading(false);
}
}
Inside the if (!res.ok) block, I want to set the error to the custom message that should be returned by the API. But I can't set it if it's not returned.
Does anyone know what I'm doing wrong here?
I am making a small social network application. I came up with a like post route and the user has to be logged in to be able to perform that action, and I have auth middleware that looks like this:
const auth = async (req, res, next) => {
// check header
const authHeader = req.headers.authorization;
if (!authHeader || !authHeader.startsWith('Bearer')) {
throw new UnauthenticatedError('Authentication invalid');
}
const token = authHeader.split(' ')[1];
try {
const payload = jwt.verify(token, process.env.JWT_SECRET);
req.user = { userId: payload.userId };
next();
} catch (error) {
throw new UnauthenticatedError('Authentication invalid');
}
};
When I pass an object with an authorization token to Axios, I get an error, here is the action.js file:
export const likePost = id => async (dispatch, getState) => {
try {
const {
userLogin: { userInfo },
} = getState();
const config = {
headers: {
Authorization: `Bearer ${userInfo.token}`,
},
};
const { data } = await axios.put(`/api/v1/post/${id}/like`, config);
dispatch({ type: POST_LIKE_SUCCESS, payload: data });
} catch (error) {
console.log(error);
dispatch({
type: POST_LIKE_FAIL,
payload: { msg: error.response.data.msg },
});
}
};
When I open the network tab in the browser, the request tab shows that I forward the headers {Authorization: Bearer .... token} and in response I get error 401.
I'm no expert with Axios, but according to the documentation, the put method uses data as the second argument and config as the third.
Maybe try to provide an empty value like null or an empty string for the second argument:
const { data } = await axios.put(`/api/v1/post/${id}/like`, null, config);
I would like to be able to redirect from registration-page to login-page on successfull registration and again from login-page to home-page afteer successfull login.
I dont know what methods to use or where to call them.
This is the register call.
app.post("/api/register", async (req, res) => {
const { username, password: plainTextPassword } = req.body;
const password = await bcrypt.hash(plainTextPassword, 10);
try {
const response = await User.create({
username,
password
})
console.log("User created", response)
} catch (error) {
if (error.code === 11000) {
return res.json({ status: "error", error: "Username already in use" })
}
throw error
}
res.json({ status: "ok" });
});
This is the script
<script>
const form = document.getElementById("reg-form");
form.addEventListener("submit", registerUser);
async function registerUser(event) {
event.preventDefault();
const username = document.getElementById("username").value;
const password = document.getElementById("password").value;
const result = await fetch("/api/register", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
username,
password
})
}).then((res) => res.json())
if (result.status === "ok") {
alert("Success");
} else {
alert(result.error)
}
}
</script>
</body>
</html>
You should return the line that redirects
return res.redirect('/UserHomePage');