Cognito is staying logged in as one user even if in incognito - node.js

I've basically followed this medium article to set up cognito in Node.JS. I used express for the UI: https://medium.com/#prasadjay/amazon-cognito-user-pools-in-nodejs-as-fast-as-possible-22d586c5c8ec
However, only one user can be logged in for the whole application. And that user becomes logged in on every browser and IP address. So the code isn't treating everyone as a separate user.
I tried putting the userPool in every function as shown below, as before it was a constant at the top of the JS file. However that did not do anything.
Here are the main functions:
app.get('/', (req, res) => {
let userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);
let cognitoUser = userPool.getCurrentUser();
if(cognitoUser === null) {
res.render('index')
}
else {
res.redirect('/dashboard')
}
});
app.get('/dashboard', (req, res) => {
let userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);
let cognitoUser = userPool.getCurrentUser();
if (cognitoUser != null) {
cognitoUser.getSession(function (err, session) {
if (err) {
req.flash('error_msg', err.message)
res.redirect('/');
}
if (session.isValid()) {
cognitoUser.getUserAttributes(function (err, result) {
if (err) {
req.flash('error_msg', err.message)
res.redirect('/');
}
let token = session['idToken']['jwtToken'];
ValidateToken(token);
res.render('dashboard', {name: result[2].getValue(), email: result[3].getValue()})
});
}
});
}
else {
req.flash('error_msg', 'You are not logged in...')
res.redirect('/');
}
})
app.post('/login', (req, res) => {
let userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);
let username = req.body.email;
let password = req.body.password;
let authenticationDetails = new AmazonCognitoIdentity.AuthenticationDetails({
Username : username,
Password : password,
});
let userData = {
Username : username,
Pool : userPool
};
let cognitoUser = new AmazonCognitoIdentity.CognitoUser(userData);
cognitoUser.authenticateUser(authenticationDetails, {
onSuccess: function (result) {
// console.log('access token + ' + result.getAccessToken().getJwtToken());
// console.log('id token + ' + result.getIdToken().getJwtToken());
// console.log('refresh token + ' + result.getRefreshToken().getToken());
req.flash('success_msg', 'Logged in');
res.redirect('/dashboard');
},
onFailure: function(err) {
req.flash('success_msg', err.message);
res.redirect('/dashboard');
console.log(err);
},
});
})
app.get('/register', (req, res) => {
let userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);
let cognitoUser = userPool.getCurrentUser();
if(cognitoUser === null) {
res.render('register')
}
else {
res.redirect('/dashboard')
}
})
app.post('/register', (req, res) => {
let userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);
let username = req.body.email;
let password = req.body.password;
let personalname = req.body.name;
let attributeList = [];
let dataEmail = {
Name : 'email',
Value : username, //get from form field
};
let dataPersonalName = {
Name : 'name',
Value : personalname, //get from form field
};
let attributeEmail = new AmazonCognitoIdentity.CognitoUserAttribute(dataEmail);
let attributePersonalName = new AmazonCognitoIdentity.CognitoUserAttribute(dataPersonalName);
attributeList.push(attributeEmail);
attributeList.push(attributePersonalName);
userPool.signUp(username, password, attributeList, null, function(err, result){
if (err) {
req.flash('error_msg', err.message);
res.redirect('/register');
return;
}
res.render('verify', {user: result.user.getUsername()})
});
})
app.post('/activation-code', (req, res) => {
let userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);
let email = req.body.username;
let activation_code = req.body.activation_code;
let userData = {
Username: email,
Pool: userPool
};
let cognitoUser = new AmazonCognitoIdentity.CognitoUser(userData);
// signing up
cognitoUser.confirmRegistration(activation_code, false, (error, result) => {
if (error) {
console.log(error)
req.flash('error_msg', error.message)
res.render('verify', {user: email})
}
else {
req.flash('success_msg', 'You have successfully verified your email. You can now log in.')
res.redirect('/')
}
});
})
I expect it to treat one browser session as one user, like a regular sign up. Thanks for any help.

Related

How to implement Node.JS model using Sequelize

I have a project with the below Model, Controller, and Route File for user. I am wanting to implement sequelize, which I have managed to partially achieve using the account files below, however, I am struggling to work out how to implement logging in and ensuring a request has a valid token usijng user.ensureToken which would become account.ensureToken.
I'm fairly new to Node.Js so I'm not even sure where to start
user.model.js
const bcrypt = require('bcrypt');
const sql = require("./db.js");
const HashBits = require("../config/auth.config.js");
const faker = require('faker');
// constructor
const User = function(user) {
this.first_name = user.first_name;
this.last_name = user.last_name;
this.mob_no = user.mob_no;
this.user_name = user.user_name;
this.password = user.password;
};
User.create = (newUser, result) => {
bcrypt.hash(newUser.password, HashBits.saltRounds, (err, hash) => {
newUser.password = hash;
sql.query("INSERT INTO users SET ?", newUser, (err, res) => {
if (err) {
// console.log("error: ", err);
result(err, null);
return;
}
newID = res.insertId;
// console.log("created user: ", { id: res.insertId, ...newUser });
result(null, { id: res.insertId, ...newUser });
});
});
};
User.authenticate = (user,result) => {
// sql.query(`SELECT * FROM customers WHERE id = ${customerId}`, (err, res) => {
sql.query(`SELECT * FROM users WHERE user_name = '${user.user_name}'`, (err, res) => {
// sql.query("SELECT * FROM users ", (err, res) => {
if (err) {
// console.log("error: ", err);
result(err, null);
return;
}
if(res.length !== 1){
// console.log("error: found multiple users");
result("error: found multiple users", null);
return;
}
// console.log("Found user: ",res[0]);
bcrypt.compare(user.password, res[0].password, function(err, res2) {
if(res2){
// console.log("Yes");
result(null,res[0]);
}else{
// console.log("On ya bike");
result("ERROR",null);
// return;
}
});
});
};
module.exports = User;
user.controller.js
const User = require("../models/user.model.js");
var jwt = require("jsonwebtoken");
const config = require("../config/auth.config.js");
// Create and Save a new User
exports.create = (req, res) => {
// Validate request
if (!req.body) {
res.status(400).send({
message: "Content can not be empty!"
});
}
// Create a User
const user = new User({
first_name: req.body.first_name,
last_name: req.body.last_name,
mob_no: req.body.mob_no,
user_name: req.body.user_name,
password: req.body.password
});
// Save User in the database
User.create(user, (err, data) => {
if (err)
res.status(500).send({
message:
err.message || "Some error occurred while creating the User."
});
else res.send(data);
});
};
exports.authenticate = (req,res) => {
if (!req.body) {
res.status(400).send({
message: "Content can not be empty!"
});
}
const user = new User({
user_name: req.body.user_name,
password: req.body.password
});
User.authenticate(user, (err,data) => {
if(err)
res.status(500).send({
message:
err.message || "Some error occurred while authenticating the User."
});
else {
var token = jwt.sign({ id: user.id }, config.secret, {
expiresIn: 86400 // 24 hours
});
// res.send(data);
res.status(200).send({
id: data.id,
username: data.user_name,
accessToken: token
});
}
});
};
exports.ensureToken = (req, res, next) => {
let token = req.headers["x-access-token"];
if (!token) {
return res.status(403).send({
message: "No token provided!"
});
}
jwt.verify(token, config.secret, (err, decoded) => {
if (err) {
return res.status(401).send({
message: "Unauthorized!"
});
}
req.userId = decoded.id;
next();
});
}
user.routes.js
module.exports = app => {
const users = require("../controllers/user.controller.js");
// Create a new User
app.post("/User", users.create);
// Login
app.post("/User/Login", users.authenticate);
};
account.model.js
const bcrypt = require("bcrypt");
module.exports = (sequelize, Sequelize) => {
const Account = sequelize.define("account", {
firstName: {
type: Sequelize.STRING
},
username: {
type: Sequelize.STRING
},
password: {
type: Sequelize.STRING,
set(value){
const hash = bcrypt.hashSync(value, 10);
this.setDataValue('password', hash);
}
}
});
return Account;
};
account.controller.js
const db = require("../models");
const Account = db.accounts;
const Op = db.Sequelize.Op;
var jwt = require("jsonwebtoken");
const config = require("../config/auth.config.js");
// Create and Save a new New
exports.create = (req, res) => {
// Validate request
if (!req.body.username) {
res.status(400).send({
message: "Content can not be empty!"
});
return;
}
// Create a Site
const account = {
firstName: req.body.firstName,
username: req.body.username,
password: req.body.password
};
Account.create(account)
.then(data => {
res.send(data);
})
.catch(err => {
res.status(500).send({
message:
err.message || "Some error occurred while creating the Account."
});
});
};
exports.authenticate = (req,res) => {
if (!req.body) {
res.status(400).send({
message: "Content can not be empty!"
});
}
const account = new Account({
username: req.body.username,
password: req.body.password
});
};
account.routes.js
module.exports = app => {
const accounts = require("../controllers/account.controller.js");
var router = require("express").Router();
app.post("/account", accounts.create);
app.post("/account/Login", accounts.authenticate);
};
you need to use jwt token for access token as you said and you are bcrypt password in model file which will be security issue you have to bcrypt password as soon as it comes in request I have implemented it in my answer remove code of password bcrypt from your model file
you have to import in your account.controller.js
const db = require("../models");
const User = db.user;
require('dotenv').config();
const Op = db.Sequelize.Op;
const errors = require('../config/errors');
const error = errors.errors;
var jwt = require("jsonwebtoken");
var bcrypt = require("bcryptjs");
module.exports = {
signup: async (req, res) => {
if (!req.body.first_name|| !req.body.lastt_name || !req.body.password) {
return res.status(200).send(error.MANDATORY_FIELDS);
}
try {
// Save User to Database
User.create({
name: req.body.name,
email: req.body.email,
mo_no: req.body.mo_no,
city: req.body.city,
password: bcrypt.hashSync(req.body.password, 8),
user_type: "admin"
}).then(function (user) {
return res.status(200).send(error.OK)
})
.catch(function (err) {
console.log(err);
return res.status(500).send(error.SERVER_ERROR)
});
} catch (e) {
console.log(e);
return res.status(500).send(error.SERVER_ERROR)
}
},
signin: async (req, res) => {
if (!req.body.email || !req.body.password) {
return res.status(200).send(error.MANDATORY_FIELDS);
}
User.findOne({
where: {
email: req.body.email
}
}).then(function (user) {
if (!user) {
return res.status(404).send(error.USER_NOT_PRESENT);
}
const passwordIsValid = bcrypt.compareSync(
req.body.password,
user.password
);
if (!passwordIsValid) {
return res.status(422).send(error.PASSWORD_MISSMATCH, {
accessToken: null
});
}
const token = jwt.sign({ id: user.id, first_name: user.first_name },
process.env.secret, {
expiresIn: 86400 // 24 hours
});
const authorities = [];
return res.status(200).send({
id: user.id,
name: user.name,
email: user.email,
accessToken: token
});
});
})
.catch(function (err) {
console.log(err)
return res.status(500).send(error.SERVER_ERROR);
});
}
}
than you have to create a separate folder for authorization like authorize.js or authJwt.js where you have to check is token is valid or not put this code in authorize.js
at decoding time secret token or password also needed which you have in .env file
const jwt = require("jsonwebtoken");
verifyToken = (req, res, next) => {
let token = req.headers["x-access-token"];
if (!token) {
return res.status(403).send(error.TOKEN_NOT_PROVIDED);
}
jwt.verify(token, process.env.secret, (err, decoded) => {
if (err) {
return res.status(401).send(error.UNAUTHORIZED);
}
req.first_name= decoded.first_name;
req.id = decoded.user_id
next();
});
};
const authJwt = {
verifyToken: verifyToken
};
module.exports = authJwt;
than you have to import authorize.js file in your routes whenever you want like this
const authorize = require('../authorize.js');
module.exports = app => {
const accounts = require("../controllers/account.controller.js");
var router = require("express").Router();
app.post("/account", accounts.create);
app.post("/account/Login",
authorize.verifyToken,accounts.authenticate);
};
it will be more effective if you genreate access token at signin time

I need to have node.js ran on all my web pages

So I have created a node server to run a website and am running into an issue with how to have it run node on the rest of the site. currently it just runs on the login page. After logging in it goes to my homepage (homepage.html). The homepage is running off nginx. How can I have everything running off node?
here is my js file (auth.js)
const mysql=require("mysql");
const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs');
const db = mysql.createConnection({
host: process.env.DATABASE_HOST,
user: process.env.DATABASE_USER,
password:process.env.DATABASE_PASSWORD,
database:process.env.DATABASE
});
exports.login = async (req, res) => {
try {
const{email, password} = req.body;
if(!email || !password){
return res.status(400).render('login', {
message:'Please provide an email and password'
})
}
db.query('SELECT * FROM users WHERE email = ?', [email], async(error, results) =>{
console.log(results);
if(!results || !(await bcrypt.compare(password, results[0].password) ) ) {
res.status(401).render('login', {
message: 'Email or Password is incorrect'
})
} else{
const id = results[0].id;
const token=jwt.sign({id:id}, process.env.JWT_SECRET, {
expiresIn: process.env.JWT_EXPIRES_IN
});
console.log("The token is: "+token);
const cookieOptions= {
expires: new Date(
Date.now + process.env.JWT_COOKIE_EXPIRES * 24 * 60 * 60 * 1000
),
httpOnly: true
}
res.cookie('jwt', token, cookieOptions);
res.status(200).redirect("http://zrgarri.it.pointpark.edu/CMPS480/homepage.html");
}
})
} catch (error) {
console.log(error);
}
}
exports.register = (req, res) => {
console.log(req.body);
const name = req.body.name;
const email = req.body.email;
const password = req.body.password;
const passwordConfirm = req.body.passwordConfirm;
db.query('SELECT email FROM users WHERE email=?', [email], async (error, results) => {
if(error){
console.log(error);
}
if(results.length > 0) {
return res.render('register', {
message: 'Email already in use.'
})
} else if(password !== passwordConfirm){
return res.render('register', {
message: 'Passwords do not match.'
});
}
let hashedPassword= await bcrypt.hash(password, 8);
console.log(hashedPassword);
db.query('INSERT INTO users SET ? ', {name: name, email: email, password: hashedPassword}, (error, results)=> {
if(error) {
console.log(error);
} else {
console.log(results);
return res.render('register', {
message: 'User Registered Successfully'
});
}
});
});
}
© 2020 GitHub, Inc.

Cognito authenticating entire EC2 instance... or so it it seems?

It appears as though when I sign into my application, it is storing the credentials locally on the EC2 server. I've quadruple checked my code and I can't figure out what the deal is. If KEVIN signs in from any device, the next user to sign in, or if someone refreshes their page they end up signed in as KEVIN. I am including all code that could potentially be involved in the issue. Outside of this problem, all of my interaction with cognito works great; no errors & no problems. Any help would be greatly appreciated. I am using Node.js, Express, AWS, and Websockets on my EC2 Instance.
// Accessed from server for route authentication before page render or redirection
const AmazonCognitoIdentity = require('amazon-cognito-identity-js');
module.exports = {
ensureAuthenticated: function(req, res, next) {
let data = { UserPoolId : 'us-east-1_7xUGRJPKq',
ClientId : '6glign6b34c806osfhnik18cb3'
};
let userPool = new AmazonCognitoIdentity.CognitoUserPool(data);
let cognitoUser = userPool.getCurrentUser();
console.log(`ensuring authentication....`);
console.log(cognitoUser);
if (cognitoUser === null) {
req.flash('error_msg', 'Please log in');
res.redirect('/login');
} else {
cognitoUser.getSession((err, session) => {
if (err) {
console.log(err);
} else {
next();
}
});
}
},
};
// Routes where I am seeing the problem
const express = require('express');
const router = express.Router();
const AmazonCognitoIdentity = require('amazon-cognito-identity-js');
const { ensureAuthenticated } = require('../config/auth.js');
router.get('/', (req, res) => {
res.redirect('/dashboard');
});
router.get('/dashboard', ensureAuthenticated, (req, res) => {
res.render('dashboard', {
layout: './layouts/dashboard-layout.ejs'
});
});
// Login authentication
router.post('/login', (req, res) => {
const loginDetails = {
Username: req.body.email,
Password: req.body.password
}
const authenticationDetails = new AmazonCognitoIdentity.AuthenticationDetails(loginDetails);
const userDetails = {
Username: req.body.email,
Pool: userPool
}
const cognitoUser = new AmazonCognitoIdentity.CognitoUser(userDetails);
cognitoUser.authenticateUser(authenticationDetails, {
onSuccess: data => {
cognitoUser.getUserAttributes(function(err, result) {
if (err) {
console.log(err);
return;
} else {
console.log('LOGIN RESULTS')
console.log(result[0].Value.toString());
let userId = result[0].Value.toString();
let userCity = result[2].Value.toString();
console.log(userId);
console.log(userCity);
res.redirect(`/dashboard/${userCity}/${userId}/`)
};
});
},
onFailure: err => {
req.flash('error_msg', 'Invalid Credentials');
console.error(err);
res.redirect('/login');
}
})
});
Thank You!
UPDATE 10/21/19: Removed function that doesn't apply to the issue.
Also do not seem to have any JWT in local storage:
Click Here for image

Postgres results.rows[0] are undefined

Not sure what I'm doing wrong, other than writing really messy code for a project I'm doing to learn Nodejs.
This used to be an async function/object but decided to get rid of try catch because my code ran twice for some reason I couldn't figure out.
Eliminating the try catch hasn't really stopped it from still running twice I think.
So the question: Why is my results.rows[0].email returning as undefined?
Sometimes it works sometimes it doesn't. I don't know why. Any help would rock.
router.post('/', (req, res, next) => {
const {password, email} = req.body
//var LoginPwd = await bcrypt.hash(password, 5);
const loginPlainPwd = password;
pool.query("SELECT password, id, email FROM companies_admins WHERE email=$1", [email], (err, results) => {
if (err)
{
throw err;
}
const dbemail = results.rows[0].email
const dbPwd = results.rows[0].password
const dbid = JSON.stringify(results.rows[0].id)
console.log('results.rows[0] = ' + results.rows[0])
console.log('loginPlainPwd = ' + loginPlainPwd)
console.log('dbPwd = ' + dbPwd)
//console.log(JSON.stringify(results.rows[0]))
//res.cookie('userId', id)
//res.sendFile(path.join(__dirname, './views/account.html'));
//bcrypt.compare(loginPlainPwd, dbPwd, (err, res) => {
if (loginPlainPwd != dbPwd)
{
console.log("loginPlainPwd != dbPwd")
/////////////////////////////////////////////?SHOULD THIS BE OUTSIE POOL.QUERY??????
console.log('err')
return res.status(401).json({
message: 'Auth failed'
});
}
else if (loginPlainPwd == dbPwd)
{
//token variable signage/creation with user data and expiration (i also included .env)
const token = jwt.sign(
{
email: dbemail,
userId: dbid,
},
process.env.JWT_KEY,
{
expiresIn: "1h"
},
);
console.log("passwords match: token created:" + token)
res.cookie('userId', token,)
console.log('cookie should be sent')
databaseJWTin(err, token, dbemail); // database function to store jwttoken from below to store jwt in database
console.log('databaseJWT function should have fired')
//had to use ../ below because path was going into routes directory for some reason
res.sendFile(path.join(__dirname, '../views/account.html'))
//return res.status(200).json({
// message: "Auth successful",
// token: token
//});
}
//res.sendFile(path.join(__dirname, './views/account.html'))
});
//res.sendFile(path.join(__dirname, './views/account.html'));
})
Please check whether result contains data in it.
router.post('/', (req, res, next) => {
const { password, email } = req.body
//var LoginPwd = await bcrypt.hash(password, 5);
const loginPlainPwd = password;
pool.query("SELECT password, id, email FROM companies_admins WHERE email=$1", [email], (err, results) => {
if (err) {
throw err;
}
if (results && results.length>0) {
const dbemail = results.rows[0].email
const dbPwd = results.rows[0].password
const dbid = JSON.stringify(results.rows[0].id)
console.log('results.rows[0] = ' + results.rows[0])
console.log('loginPlainPwd = ' + loginPlainPwd)
console.log('dbPwd = ' + dbPwd)
//console.log(JSON.stringify(results.rows[0]))
//res.cookie('userId', id)
//res.sendFile(path.join(__dirname, './views/account.html'));
//bcrypt.compare(loginPlainPwd, dbPwd, (err, res) => {
if (loginPlainPwd != dbPwd) {
console.log("loginPlainPwd != dbPwd")
/////////////////////////////////////////////?SHOULD THIS BE OUTSIE POOL.QUERY??????
console.log('err')
return res.status(401).json({
message: 'Auth failed'
});
}
else if (loginPlainPwd == dbPwd) {
//token variable signage/creation with user data and expiration (i also included .env)
const token = jwt.sign(
{
email: dbemail,
userId: dbid,
},
process.env.JWT_KEY,
{
expiresIn: "1h"
},
);
console.log("passwords match: token created:" + token)
res.cookie('userId', token)
console.log('cookie should be sent')
databaseJWTin(err, token, dbemail); // database function to store jwttoken from below to store jwt in database
console.log('databaseJWT function should have fired')
//had to use ../ below because path was going into routes directory for some reason
res.sendFile(path.join(__dirname, '../views/account.html'))
//return res.status(200).json({
// message: "Auth successful",
// token: token
//});
}
//res.sendFile(path.join(__dirname, './views/account.html'))
}
});
//res.sendFile(path.join(__dirname, './views/account.html'));
})

Error while using Node.js.

This is my model.
UserApiSchema.statics.createApi = function(user,fn){
var instance = new UserApi();
instance.user = user;
instance.apiKey = "asdasdacasdasasd";
console.log("username is " + user.username);
instance.save(function(err){
fn(err,instance);
});
};
UserSchema.statics.newUser = function (email, password,username, fn) {
var instance = new User();
var apiInstance = new UserApi();
instance.email = email;
instance.password =password;
instance.username = username;
instance.save(function (err) {
fn(err, instance);
});
};
This is my controller-users.js:
app.post(
'/signup/',
function(req, res) {
{console.log(req.body.username);
User.newUser(
req.body.email, req.body.password,req.body.username,
function (err, user) {
if ((user)&&(!err)) {
console.log(user.username)
UserApi.createApi(
user,function(err,userapi){
if((!err)){
res.send("APi created")
}
else{
if(err.errors.apiKey){
res.send(err)
}
}
});
req.session.regenerate(function(){
req.session.user = user._id;
res.send("Success here!");
});
} else {
if (err.errors.email) {
res.send(err)
console.log(req.body.password);
console.log(req.body.email);
console.log(req.body);
}
if (err.errors.username) {
res.send(err)
console.log(req.body.password);
console.log(req.body.email);
console.log(req.body);
}
}
});
}
});
The concept is once the user-name/password is accepted, an API key is stored along with the username. Though, the username payload is getting accepted, when I do the UserApiSchema call to generate the api, no such api is generated. No errors either.
Might be real basic ... but, did you create the objects needed?
UserApiSchema = {};
UserApiSchema.statics = {};
UserApiSchema.statics.createApi = function(user,fn){ ...}
If so ... are they in a module?
Did you export them from the module?
exports.userApiSchema = UserApiSchema;
Did you import them in controller-users.js?
var userApiSchema = require('./UserApiSchema.js');

Resources