When i trying to run my API in postman it is working fine and sessions are getting maintained. But when i am trying to run it from UI Part the login session is not working.
This is my Login API from where i am login into
app.post('/user/login', (req, res, next) => {
const body = req.body;
let email = body.email;
let password = body.password;
const userDetails = db.collection(userProfiles);
userDetails.findOne({email: email}, function (err, user) {
if (err) {
return next(err);
} else if (!user) {
return res.status(400).send({
status: 'error',
message: 'user does not exist'
});
} else {
if (user.password == password) {
user_object = user;
req.session.user = user;
return res.send({
user_obj: user,
status: 'success',
message: 'Successfully logged in'
});
} else {
return res.status(400).send({
status: 'error',
message: 'Wrong Password'
})
}
}
return res.send(user);
});
});
This is my session API from where i am sending user req.session.user on calling this api
app.get('/user/dashboard', function (req, res) {
if (!req.session.user) {
return res.status(400).send({
data:'need to be logged in'
});
}
return res.status(200).send({
data:req.session.user
});
});```
The below is the javascript file from where i am trying to call the user stores in req.session.user
`
async function fetchUserId(){
let cookie = document.cookie;
let res = await fetch('http://127.0.0.1:8080/user/dashboard',
{redirect: 'follow',
headers:{
"Cookie":cookie
}});
let userJson = await res.json();
console.log(res);
console.log(userJson);
//return userJson;
};
`
when i hit the login API from Postman it is maintaining session and working fine but when i do the same from UI from browser it is giving error status 400 every time.
You can do a
fetch(url, options).then(function(res) { console.log(res} )
and
app.get('/user/dashboard', function (req, res) {
console.log(req.headers)
if (!req.session.user) {
return res.status(400).send({
data:'need to be logged in'
});
}
return res.status(200).send({
data:req.session.user
});
});
To check is the cookie really there and where is the user object.
And you can check your browsers dev console to see if the cookie is updating.
I see that is fetch request you put a cookie in your header. But than at the API you are looking for a user at req.session.user. Although the cookie is in req.header["Cookie"].
Related
I am learning how to implement user authentication using passport.js. I have a basic passport "local" strategy set up on the server side and so far just a single POST route to log a user in. This all works exactly as intended when troubleshooting with insomnia but when I make the same request from the browser I get a message missing credentials. This message is coming from console.log(info) in controllers/auth.js.
I have tried including credentials in the fetch request as seen below but I must be missing something else or including them incorrectly. I have also changed the variable names from 'email' to 'username' since I read that was the default for passport.js.
From what I can tell in Chrome dev tools, the request body is formatted correctly and I am hitting the proper endpoint.
controllers/auth.js
const express = require("express");
const router = express.Router();
const passport = require("passport");
router.post("/register_login", (req, res, next) => {
passport.authenticate("local", function(err, user, info) {
console.log(info)
if (err) {
return res.status(400).json({ errors: err });
}
if (!user) {
return res.status(400).json({ errors: "No user found" });
}
req.logIn(user, function(err) {
if (err) {
return res.status(400).json({ errors: err });
}
return res.status(200).json({ success: `logged in ${user.id}` });
});
})(req, res, next);
});
module.exports = router;
passport/setup.js
const bcrypt = require('bcrypt');
const { User } = require('../models');
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser((id, done) => {
User.findById(id, (err, user) => {
done(err, user);
});
});
// Local Strategy
passport.use(new LocalStrategy((username, password, done) => {
// Match User
User.findOne({ email: username })
.then(user => {
// Create new User
if (!user) {
return done(null, false, { message: 'No user found!!'})
// Return other user
} else {
// Match password
bcrypt.compare(password, user.password, (err, isMatch) => {
if (err) throw err;
if (isMatch) {
return done(null, user);
} else {
return done(null, false, { message: 'Wrong password' });
}
});
}
})
.catch(err => {
return done(null, false, { message: err });
});
})
);
module.exports = passport;
client side fetch
const handleLogin = async (evt) => {
evt.preventDefault();
const response = await fetch('/auth/register_login', {
method: 'POST',
credentials: 'include',
withCredentials: true,
body: JSON.stringify({
"username": "test#email.com",
"password": "password"
})
})
return response;
};
Oof, that was a simple one...
I was reading the "Content-Type" in Chrome dev tools however I was reading the "Response Headers" thinking they were the "Request Headers". The issue is that I was sending text instead of json.
Changing the client side fetch to the snippet below resolved the issue.
client side fetch
const handleLogin = async (evt) => {
evt.preventDefault();
const response = await fetch('/auth/register_login', {
method: 'POST',
credentials: 'include',
withCredentials: true,
headers: {
'Content-Type': 'application/json' // <--add this
body: JSON.stringify({
"username": "test#email.com",
"password": "password"
})
})
return response;
};
const router = require("express").Router();
const mongoose = require("mongoose");
const User = require("../models/Users");
const bcrypt = require("bcrypt");
const jwt = require("jsonwebtoken");
// Route 1: create new user at /api/createuser
router.post("/createuser", async (req, res) => {
try {
console.log(req.body);
const salt = await bcrypt.genSaltSync(10);
const hash = await bcrypt.hashSync(req.body.password, salt);
password = hash;
const user = new User({
name: req.body.name,
email: req.body.email,
password: password,
});
user
.save()
.then(() => {
res.json({ message: "User created successfully" });
})
.catch((err) => {
res.json({ message: "Error: " + err });
});
console.log(password);
} catch (err) {
res.json({ message: err });
}
});
// Route 2: Login user at /api/login
router.post("/login", async (req, res) => {
try {
console.log("login endpoint triggered");
const user = await User.findOne({ email: req.body.email });
if (!user) {
res.json({ message: "User does not exist" });
}
const passwordIsValid = await bcrypt.compare(
req.body.password,
user.password
);
if (!passwordIsValid) {
res.json({ message: "Invalid password" });
} else {
const data = {
id: user._id,
};
const token = await jwt.sign(data, process.env.SECRET);
res.json(token);
}
} catch (error) {
res.json({ message: error });
}
});
module.exports = router;
Whenever I am testing the login endpoint, my app crashes if i try to put incorrect password or unregistered email.
It says Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
I have only sent one response to the client even then it is showing this error.
In the terminal, it is showing error at catch block of login endpoint.
Can anyone look into it and tell me why am i getting this error.
Make sure that when the response is an error, the rest of the middleware is not executed any more. For example, put a return before the res.json statement:
if (!user) {
return res.json({ message: "User does not exist" });
}
Otherwise, the "Invalid password" json might get issued after this one, but two res.jsons in one response lead to the observed error.
We're trying to integrate Passport authentication with out React app, and we're using React Router.
On the first submission of correct user credentials, the server receives the post, adds a session to our database, and seems to send a response, but the client doesn't update. The username and password show up in the url as a query string. Then when we resend the credentials without removing the query string from the url, the client is able to receive the response from the server.
In other words, if we don't refresh before submitting the login info again, it works.
This is the click handler that our form utilizes:
const handleClick = () => {
return axios.post('/login', { username, password })
.then(({ data }) => {
const { message } = data;
if (message === 'success') {
const { user } = data;
setUserId(user.id);
setUser(user);
}
setAuthStatus(message);
})
.catch(err => console.error(err));
};
This is our server route that is hit on every post request:
loginRouter.post('/', (req, res, next) => {
console.log('stop');
passport.authenticate('local', (err, user, info) => {
const { invalidPassword } = info || false;
if (err) {
return next(err); // will generate a 500 error
}
if (!user) {
return res.send({ message: 'invalidUser' });
}
if (invalidPassword) {
return res.send({ message: 'invalidPassword' });
}
req.login(user, loginErr => {
if (loginErr) {
return next(loginErr);
}
return res.send({ user, message: 'success' });
});
})(req, res, next);
});
This is our Passport Local Strategy that uses Sequelize:
passport.use(new LocalStrategy(
(username, password, cb) => {
User.findOne({ where: { username } })
.then((user) => {
if (!user) {
return cb(null, false);
}
if (validPassword(password, user.hash, user.salt)) {
return cb(null, user);
}
return cb(null, false, { invalidPassword: true });
})
.catch(err => {
cb(err);
});
},
));
Having trouble debugging this... We suspect the error is on the client side and may have to do with React-Router. We are using React-Router and Passport for the first time on this project.
Any help is appreciated!
Welp... All we were missing was event as a parameter in handleClick and event.preventDefault().
I have a login form that authenticates using postgresql I'm trying to check if users exists then redirect the client to the other page. The code is:
app.post('/login', (req, res) => {
var Enteredusername = req.body.username;
var Enteredpassword = req.body.password;
pool.query("SELECT * FROM tbl_users WHERE username = $1 AND password = $2", [Enteredusername, Enteredpassword], (err, result) => {
if (err) return console.log('error in query', err);
// need to check if user exists
let user = (result.rows.length > 0) ? result.rows[0] : null;
if (!user) {
req.flash('notify', 'This is a test notification.')
res.render('login', {
messages: req.flash('Username or Password is incorrect !')
});
return res.redirect('/login')
}
res.redirect('/posts')
});
});
And I got the error:
_http_outgoing.js:470
throw new ERR_HTTP_HEADERS_SENT('set');
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client.
How Can I fix it?
It's the async behavior of javascript res.redirect('/posts') is executed before req.flash and res.render you can hack it like this :
req.session.userId = Enteredusername;
if (!user) {
req.flash('notify', 'This is a test notification.')
res.render('login', {
messages: req.flash('Username or Password is incorrect !')
});
return res.redirect('/login')
}else{
return res.redirect('/posts')
}
I am trying to fetch some data from my server and when testing the request with Postman it works great and I getting data back. But then when I trying to implement the request in my app Im getting back an empty object with undefined properties
CODE:
fetchUserData = (user) => {
axios.post('api', {
username: user
})
.then((res) => {
this.setState({
credit: res.credit,
points: res.points
})
console.log(`this is user stats\ncredit:${res.credit}\npoints:${res.points} for the user: ${user}`)
})
}
router.post('/', (req, res) => {
UserData.findOne({
username: req.body.username,
},
(err, user) => {
if (err) {
console.log('Error in saving user to mongodb: ' + err);
res.send(err);
}
if (user) {
if(user.username === req.body.username) {
console.log('fetching data for: ' + user.username);
console.log(user);
res.send(user);
}
}
});
})
RESPONSE FROM POSTMAN:
{"_id":"5afd9bXXXXXXX664a5af","username":"check","credit":1,"points":0,"__v":0}
RESPONSE ON APP CONSOLE:
this is user stats credit:undefined points:undefined for the user: check
to read data from the response I should have to use 'res.data.something' and not res.something