jsonwebtoken doesn't retrieve a token - javascript

I am using nodejs and sequelize to create simple user registration, I already did the login and register, but when login is a success I don't get any token.
I have tried to console.log the token to see if I get some result, but there is no response in the console related to the token.
Here is my code:
var express = require('express');
var User = require('../../models').User;
var router = express.Router();
var jwt = require('jsonwebtoken');
var app = require('../../app');
/*var token = jwt.sign(user, app.get('superSecret'), {
expiresInMinutes: 1440 // expires in 24 hours
});*/
router.post('/', function (req, res, next) {
if (JSON.stringify(req.body) == "{}") {
return res.status(400).json({ Error: "Login request body is empty" });
}
if (!req.body.username || !req.body.password) {
return res.status(400).json({ Error: "Missing fields for login" });
}
// search a user to login
User.findOne({ where: { username: req.body.username} }) // searching a user with the same username and password sended in req.body
.then(function (user) {
if (user && user.validPassword(req.body.password)) {
//return res.status(200).json({ message: "loged in!" }); // username and password match
// create a token
var token = jwt.sign(user, app.get('superSecret'), {
expiresInMinutes: 1440 // expires in 24 hours
});
// return the information including token as JSON
res.json({
success: true,
message: 'Enjoy your token!',
token: token
});
}
else{
return res.status(401).json({ message: "Unauthorized" }); // if there is no user with specific fields send
}
}).catch(function (err) {
return res.status(500).json({ message: "server issues when trying to login!" }); // server problems
});
});
module.exports = router;

You should use express-jwt library. https://www.npmjs.com/package/express-jwt
It's middleware for express. Example:
var jwt = require('express-jwt');
app.get('/protected',
jwt({secret: 'shhhhhhared-secret',
credentialsRequired: false,
getToken: (req) => req.cookies.id_token // when cookies are using. 'id_token' is cookie's name
}),
function(req, res) {
if (!req.user.admin) return res.sendStatus(401);
res.sendStatus(200);
});
Also you may write as app.use(...) or app.anyRequest(...)

Related

Cannot read properties of undefined (reading 'id')

I have a auth.js file And a middleware named as fetchuser code given beolow
Can anyone please tell me why am i getting this error.
I am using express js and mongoose but this error is occured during sending token to the user and verify the user whether is user logged in or not.
auth.js
const express = require('express');
const User = require('../models/User');
const router = express.Router();
const { body, validationResult } = require('express-validator');
const bcrypt = require('bcryptjs'); // it is used for password hashing
const jwt = require('jsonwebtoken');
const fetchuser=require('../middleware/fetchuser');
// Route:1 - Create a User using :POST. "/api/auth/createuser". NO Login Required.
router.post('/createuser', [
body('email', 'Enter valid email').isEmail(),
body('name', 'Enter valid email').isLength({ min: 3 }),
body('password').isLength({ min: 5 })
], async (req, res) => {
// Check fo vaidation whether is any rule(defined in User model) breaked or not
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
// Check Whether user with same email id exist or not
try {
let user = await User.findOne({ email: req.body.email });
if (user) {
return res.status(400).json({ error: "Sorry user with same email id already exist" });
}
// hashing of password
const salt = await bcrypt.genSalt(10);
const securePassword = await bcrypt.hash(req.body.password, salt);
// create A new User
user = await User.create({
name: req.body.name,
email: req.body.email,
password: securePassword
})
// returning user id in Token
const JWT_secret = "Rishiisa#boy";
const data = { user:{id: user.id} };
const auth_token = jwt.sign(data, JWT_secret);
res.json({ auth_token });
}
catch (error) {
console.error(error.message);
res.status(500).send("Internal server error");
}
})
// Route:2 - Login a User using credential. "/api/auth/login". NO Login Required.
router.post('/login', [
body('email', 'Enter valid email').isEmail(),
body('password', 'password can not be blank').exists(),
], async (req, res) => {
// Check for vaidation according to the rule defined at line no. 53, 54;
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
// destructure the email and password from body request
const { email, password } = req.body;
try {
// Checking whether email is exist or not
let user = await User.findOne({ email });
if (!user) {
return res.status(400).json({ error: "Please try to login using correct credentials" });
}
// Now Comparing password with help of bcryptjs
const comparepassword = await bcrypt.compare(password, user.password);
if (!comparepassword) {
return res.status(400).json({ error: "Please try to login using correct credentials" });
}
// Now if user enter coorect password and login then user got logged in;
// And We will send authtoken to user;
// returning user id in Token
const JWT_secret = "Rishiisa#boy";
const data = { user:{id: user.id} };
const auth_token = jwt.sign(data, JWT_secret);
res.json({ auth_token });
}
catch (error) {
console.error(error.message);
res.status(500).send("Internal server error");
}
})
// Route:3 - Get Loggedin User details using:POST "/api/auth/getuser" Login required
router.post('/getuser', fetchuser, async (req, res) => {
try {
const userid = req.user.id;
const user = await User.findById(userid).select("-password");
res.send(user);
} catch (error) {
console.error(error.message);
res.status(500).send("Internal server error");
}
})
module.exports = router
middleware:
fetchuser.js
const jwt = require('jsonwebtoken');
const JWT_secret = "Rishiisa#boy";
const fetchuser = (req, res, next) => {
// Get the user from jwt token and add user id to req object
const token = req.header('auth_token');
if (!token) {
res.status(401).send({ error: "Please authenticate using a valid token" });
}
try {
const data = jwt.verify(token, JWT_secret);
req.user = data.user;
next();
} catch (error) {
res.status(401).send({ error: "Please authenticate using a valid token" });
}
}
module.exports = fetchuser;
In auth.js, where you wrote: "const data = { user:{id: user.id} };" Try changing user.id to user._id, since in MongoDB the user id is referred to as '_id'.
Let me know if that works.
I've had problems sending jwt token back and even verifying it, but all is good on my side now.
Also, below is my (inspired) method of going about this:
router.post('/register', (req, res)=>{
const { username, password } = req.body;
const user = new User({
username,
password
});
bcrypt.genSalt(10, (err, salt)=>{
bcrypt.hash(user.password, salt, (err, hash)=>{
if(err) throw err;
user.password = hash;
user.save()
.then(user=>{
jwt.sign(
{ id: user._id },
process.env.jwtSecret,
{ expiresIn: 3600 },
(err, token) =>{
if(err) throw err;
res.status(200)
}
)
})
})
})
})

JWT in http only cookie is getting undefined

I am setting access_token in login route but I am getting undefined.
Lines commented below in the code gives undefined why so? How to access the cookie when it is set ? There is another GET route /transactions which gets called on home page after login is success in that route as well I am getting undefined why so? I have also used cookie-parser in server.js file but still not working
transaction GET route https://pastebin.com/DP0NZL5W
const express = require('express');
const router = express.Router();
const jwt = require('jsonwebtoken');
const User = require('../models/userSchema');
router.post('/login', (req, res) => {
const {email, password} = req.body;
console.log("Server Login email: ", email);
console.log("Server Login password: ", password);
User.find({email: email})
.exec()
.then(user => {
console.log("User login user: ", user);
if(user.length < 1){
console.log("user length less")
return res.status(401).json({
message: 'Auth failed'
});
}
bcrypt.compare(password, user[0].password, (err, result) => {
if(err){
return res.status(401).json({
message: 'Auth failed'
});
}
if(result){
const token = jwt.sign({
email: user[0].email,
userId: user[0]._id
}, 'secret', {
expiresIn: "1h"
})
console.log("Cookie token: ", token);
res.cookie('access_token', token, { maxAge: 9000000, httpOnly: true });
// console.log("req.cookies: ", req.cookies)
// console.log("req.cookies['access_token']: ", req.cookies['access_token'])
return res.status(200).json({
message: 'Auth successful',
token: token
})
}
return res.status(401).json({
message: 'Auth failed'
});
})
})
.catch(err => {
console.log(err);
res.status(500).json({
error: err
})
})
});
app.use({
credentials: true, // enable cookie receiving
origin: "url of client side" // how can use your api
})

Restful API: How to display specific data in Node/Express app?

I am building a simple Node/Express app to login a user. Before user can login the app must check if the email provided exists in the database.
The structure of my app is like this:
* db/data.js
* app.js // server
I want to login a user
const data = [
{
id: 1,
email: 'xyz#xyz.com',
fist_name: 'hekw',
last_name: 'xyz',
password: 'usr$#',
},
];
export default data;
import express from 'express';
import bodyParser from 'body-parser';
import data from './db/data';
// set up the express app
const app = express();
// Parse incoming requests data
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
/**
* Sign in a user
* #param {object} req
* #param {object} res
*/
app.post(`/login`, (req, res) => {
const findUserByEmail = (email) => {
for (let i = 0; i < data.length; i++) {
return data[i]['email'] === email ? true : false;
}
};
if (findUserByEmail(req.body.email)) {
return res.status(409).send({
success: false,
message: 'email already exists',
//findUserByEmail(req.body.email)
//data,
});
}
const port = 5000;
app.listen(port, () => {
// console.log(`The server running on port ${PORT}`);
});
export default app;
I tried but I couldn't display info of a signed user. How can I achieve it?
This is what I need:
"status":"success"
"data": {
"id": 1,
"email":"xyz#xyz.com",
"first_name": "hekw",
"last_name": "xyz",
"password": "usr$#"
}
Edit
I've implemented the code below, but I want now to check for both email and password.
const findUserByEmail = (email) => data.find(user => user.email === email);
const foundUser = findUserByEmail(req.body.email);
if (!foundUser) {
return res.status(404).send({
status: 'error',
error: 'user does not exist, register first',
});
}
if (foundUser) {
// if password OK then diplay success message. How do I access pwd field here?
return res.status(200).send({
status: 'success',
data: foundUser,
});
}
First of all, I highly recommend using the MVC pattern and create a model for each separate data model. Also, an encryption method such as Bcrypt to encrypt the passwords before storing them to the database and using a token-based approach to handle user authentication.
For the purpose of the example, I provide a solution with the JWT and Bcrypt to help understand the process better, also for people who are looking for a more detailed answer. We can pass a middleware into routes to check the user is authenticated or not then fetch the proper data for the user.
const express = require('express');
const app = express();
const router = express.Router();
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
// This user model can be replaced with your data file, in your sample
const User = require('../models/userModel');
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json()); // Always return JSON for the rest api
// Awlays set headers to controll the access
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization');
if (req.method === 'OPTIONS') {
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE');
return res.status(200).json({});
}
next();
});
// This is the user controller, below return it inside the route
const loginUserController = (req, res) => {
User.findOne({ email: req.body.email }) // find just one record by the email received from the user
.exec() // Use this to make a promise
.then(user => {
if (user.length < 1) { // check if the user found
return res.status(401).json({ // Check if email is not valid
message: 'Authentication Failed! Wrong login information used!'
})
}
// If status code is not 401 and user is found, then compare the password with DB version and pass "err" and "success" parameters
// user.password is the db password
bcrypt.compare(req.body.password, user.password, (err, success) => {
if (err) {
return res.status(401).json({
message: 'Authentication Failed! Wrong login information used!'
})
}
if (success) {
// Then we sign JWT if password matched
// process.env.JWT_KEY is our server jwt token
const token = jwt.sign({
email: user.email,
userId: user._id
}, process.env.JWT_KEY, {
expiresIn: '2d' // we can set the expire date (see th e docs for more info)
});
// Finally we return our token to store into user's browser cookie
// or we can just return the data, but its better to use jwt token and use it everywhere you want to get user data
return res.status(200).json({
message: 'Welcome to My App!',
data: user
token
});
}
// Here we return another 401 if the were no err or success
res.status(401).json({
message: 'Authentication Failed! Wrong login information used!'
})
})
})
.catch(err => {
// Use can create an error controller and put a switch inside of it to check response status code then return proper message
errorController(req, res, res.status, 'ANY');
})
}
// Finally we use our router to post and return login controller
router.post('/login', (req, res) => {
return loginUserController(req, res);
});
app.listen(process.env.PORT || 3000);
There are more advanced configurations, but for simplicity of the example, I provided a simple way to do the correct way (in my opinion). Hope it help.
Packages used in this example
jsonwebtoken
Bcrypt
Your code is not working. Following will not find the user object in your data array.
const findUserByEmail = (email) => {
for (let i = 0; i < data.length; i++) {
return data[i]['email'] === email ? true : false;
}
};
You can find the user like this:
const findUserByEmail = (email) => data.find((datum) => datum.email === email);
Assuming you are sending a POST request with email set correctly. You can use the following code to achieve the result you want:
const findUser = (email, pass) => data.find((datum) => datum.email === email && datum.password === pass);
let foundUser = findUser(req.body.email, req.body.password);
if (foundUser) {
return res.status(200).json({
"status":"success"
"data": foundUser
});
}
res.status(404).json({
"status": "Not Found"
"data": foundUser
});

Get token decrypted data

I am struggling with how to get my user decrypted data for the current user, basicly everytime a user does login he get a token at the moment.
After i login i can capture a phote and send it to the server, following my code you guys can see that this request needs a token to work.
Basicly i have a problem related to my app.js(starting file) i try to set a app.use that needs a token for all the routes that comes after the register and login, like this:
app.use('/',require('./routes/index'));
app.use(jwtPermission);
router.use('/fotos',fotos);
my jwt permission file:
var jwt = require('jsonwebtoken');
var jwtConfig = require('../config/jwt');
module.exports = function(req, res, next) {
console.log("entered");
// check header or url parameters or post parameters for token
var token = req.body.token || req.query.token || req.headers['x-access-token'];
console.log(req.headers['x-access-token']);
// decode token
if (token) {
// verifies secret and checks exp
jwt.verify(token,jwtConfig.secret, function (err, decoded) {
if (err) {
return res.json({ success: false, message: 'Failed to authenticate token.' });
} else {
// if everything is good, save to request for use in other routes
req.decoded = decoded;
next();
}
});
} else {
// if there is no token
// return an error
return res.status(403).send({
success: false,
message: 'No token provided.'
});
}
}
router index(connection to authentication and fotos files)
var express = require('express');
var router = express.Router();
router.use(function timeLog(req, res, next) {
console.log('Time: ', Date());
console.log('Request Type:', req.method);
console.log('Request URL:', req.originalUrl);
next(); //passa a solicitação para a próxima função de middleware na pilha
});
router.use('/',require('./authentication'))
router.use('/fotos',require('./fotos'));
router.use(function(req,res,next){
return res.status(404).json({Error:"Invalid Url"});
})
module.exports = router;
when i point to /fotos it doesn't enter the jwtPermission as i want, what is wrong?
you can add your token validation middleware before function that handles some route. For example:
router.use('/fotos', jwtAuthentication, require('./fotos'));

Compare passwords BcryptJS

So I'm trying to build a very basic user login. I'm trying to create a user, then login with those credentials and get back a JSON Web Token. Where I'm stuck is trying to compare the passwords then send a response.
Steps:
Create User:
enter email and password
salt/hash user password
store user into database
return success
Login
find user by request email value
if found compare passwords
passwords good send JSON Web Token
User Model
email:{
type: String,
required: true,
unique: true
},
password: {
type: String,
required: true
}
User Routes
var express = require('express');
var router = express.Router();
var jwt = require('jsonwebtoken');
var bcrypt = require('bcryptjs');
// Create User
...
bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash("superSecret", salt, function(err, hash) {
user.password = hash;
user.save();
res.json({success: true, message: 'Create user successful'});
});
});
...
// Login
...
bcrypt.compare(req.body.password, 'superSecret', function(err, res) {
if(req.body.password != user.password){
res.json({success: false, message: 'passwords do not match'});
} else {
// Send JWT
}
});
So the two problems here is that, I can't send a response nor can I compare the password. Just completely stuck on this, any help would be greatly appreciated.
As described in the doc, you should use bcrypt.compare like that:
bcrypt.compare(req.body.password, user.password, function(err, res) {
if (err){
// handle error
}
if (res) {
// Send JWT
} else {
// response is OutgoingMessage object that server response http request
return response.json({success: false, message: 'passwords do not match'});
}
});
And here is a nice post about Password Authentication with Mongoose (Part 1): bcrypt
//required files
const express = require('express')
const router = express.Router();
//bcryptjs
const bcrypt = require('bcryptjs')
//User modal of mongoDB
const User = require('../../models/User')
//Post request for login
router.post('/', (req, res) => {
//email and password
const email = req.body.email
const password = req.body.password
//find user exist or not
User.findOne({ email })
.then(user => {
//if user not exist than return status 400
if (!user) return res.status(400).json({ msg: "User not exist" })
//if user exist than compare password
//password comes from the user
//user.password comes from the database
bcrypt.compare(password, user.password, (err, data) => {
//if error than throw error
if (err) throw err
//if both match than you can do anything
if (data) {
return res.status(200).json({ msg: "Login success" })
} else {
return res.status(401).json({ msg: "Invalid credencial" })
}
})
})
})
module.exports = router
If we you to use bcryptjs in browser(HTML) then you can add bcryptjs CDN to do this.
CDN - https://cdn.jsdelivr.net/npm/bcryptjs#2.4.3/dist/bcrypt.js
Example-
HTML- (Add above CDN in tag)
JS-
var bcrypt = dcodeIO.bcrypt;
/** One way, can't decrypt but can compare */
var salt = bcrypt.genSaltSync(10);
/** Encrypt password */
bcrypt.hash('anypassword', salt, (err, res) => {
console.log('hash', res)
hash = res
compare(hash)
});
/** Compare stored password with new encrypted password */
function compare(encrypted) {
bcrypt.compare('aboveusedpassword', encrypted, (err, res) => {
// res == true or res == false
console.log('Compared result', res, hash)
})
}
If you want to do same in Nodejs
/** Import lib like below and use same functions as written above */
var bcrypt = require('bcryptjs')
From what I can see your logic is correct.
If you are using mongoose I suggest you to use the pre 'save' hook.
User Schema
userSchema.pre('save', function(next) {
// only hash the password if it has been modified (or is new)
if (!this.isModified('password')) {
return next();
}
// generate a salt
return bcrypt.genSalt(10, function(error, salt) {
if (error) {
return next(error);
}
// hash the password using the new salt
return bcrypt.hash(this.password, salt, function(error, hash) {
if (error) {
return next(error);
}
// override the cleartext password with the hashed one
this.password = hash;
return next();
});
});
});
userSchema.methods.comparePassword = function(passw, cb) {
bcrypt.compare(passw, this.password, function(err, isMatch) {
if (err) {
return cb(err, false);
}
return cb(null, isMatch);
});
};
And in your routes:
Login
...
return user.comparePassword(password, function(error, isMatch) {
var payload = {
iat: Math.round(Date.now() / 1000),
exp: Math.round((Date.now() / 1000) + 30 * 24 * 60),
iss: 'Whatever the issuer is example: localhost:3000',
email: user.email
};
var token = jwt.encode(payload, 'secret');
if (isMatch && !error) {
// if user is found and password is right create a token
return res.json({
success: true,
token: `JWT ${token}`,
user: user,
msg: 'Authentication was succesful'
});
}
return next({code: 401, msg: 'Password is incorrect'});
});
});
Create user
// Pre hook will take care of password creation
return user.save()
.then(function(user) {
var payload = {
iat: Math.round(Date.now() / 1000),
exp: Math.round((Date.now() / 1000) + 30 * 24 * 60),
iss: 'Whatever the issuer is example: localhost:3000',
email: user.email
};
var token = jwt.encode(payload, 'secret');
return res.status(201).json({user, token: `JWT ${token}`, msg: 'User was succesfully created'});
})
.catch((err) => next(err));
bcrypt.compare(req.body.password, user.password, function(err, results){
if(err){
throw new Error(err)
}
if (results) {
return res.status(200).json({ msg: "Login success" })
} else {
return res.status(401).json({ msg: "Invalid credencial" })
}
})
const bcrypt = require("bcryptjs");
const salt = bcrypt.genSaltSync(10);
const hashPassword = (password) => bcrypt.hashSync(password, salt);
const comparePassword = (password, hashedPassword) =>
bcrypt.compareSync(password, hashedPassword);
bcrypt.compare(req.body.password, user.password)
.then(valid => {
if (!valid) {
return res.status(401).json({ message: 'Paire login/mot de passe incorrecte' });
}
res.status(200).json({
userId: user._id,
token:jwt.sign(
{userId: user._id},
process.env.ACCESS_TOKEN_SECRET_KEY,
{expiresIn:'24h'}
),
message: 'connected'
});
})
.catch(error => res.status(500).json({ error }));
enter code here

Categories

Resources