I'm currently trying my hand at "basic authentication" for users. I can't now get a http response back to my query. The path of the request is 'AuthenticationService' --> 'UserService'. But from 'UserService' I can't get to 'UserRoute' and therefore not to 'httpServer'. The correct order should be: AuthenticationService -->UserService --->Userroute-->httpServer If I change in AuthenticationRoute.js router.post('/', authenticate); to router.post('/authenticate', authenticate) I get a http response, but I dont transmit any data....What do I have to do ?
UserService.js
async function authenticate({ username, password }) {
const user= User.find({userName:username} && {password:password})
/* const user = User.find(u => u.userName === so && u.password === password); */
if (user) {
const { password, ...userWithoutPassword } = user;
return userWithoutPassword;
}
}
module.exports = {
authenticate
}
UserRoute.js
var userService = require('./UserService')
router.post('/', authenticate);
function authenticate(req, res, next) {
userService.authenticate(req.body)
.then(user => user ? res.json(user) : res.status(400).json({ message: 'Username or password is incorrect' }))
.catch(err => next(err));
}
module.exports = router;
AuthenticationService.js
async function basicAuth(req, res, next) {
// make authenticate path public
if (req.path === '/') {
return next();
}
if (!req.headers.authorization || req.headers.authorization.indexOf('Basic ') === -1) {
return res.status(401).json({ message: 'Missing Authorization Header' });
}
// verify auth credentials
const base64Credentials = req.headers.authorization.split(' ')[1];
const credentials = Buffer.from(base64Credentials, 'base64').toString('ascii');
const [username, password] = credentials.split(':');
console.log(username+password);
const user = await userService.authenticate({ username, password });
if (!user) {
return res.status(401).json({ message: 'Invalid Authentication Credentials' });
}
req.user=user
next();
}
module.exports = {
basicAuth
}
AuthenticationRoute.js
var express = require('express');
var router = express.Router();
var authenticationService=require('./AuthenticationService')
router.post('/authenticate', authenticationService.basicAuth);
module.exports=router;
httpServer.js
const userRoutes = require('./endpoints/user/UserRoute')
const authenticationRoutes= require('./endpoints/authentication/AuthenticationRoute')
var axios = require('axios');
app.use(authenticationRoutes);
app.use(userRoutes);
The request I try to send is:
POST http://localhost:8080/authenticate
Authorization: Basic YWRtaW46MTIz
Related
I put the wrong password but it gets login successfully and the data which is inside a particular user is as a new user login. I want you to please tell me a error.
Link of an online hosted project: NOTEBOOK/login
Link of GitHub repository: GITHUB/notebook
The login folder is inside routes/auth.js
const express = require('express');
const router = express.Router();
const User = require('../models/User')
const { body, validationResult } = require('express-validator');
var bcrypt = require('bcryptjs');
var jwt = require('jsonwebtoken');
let fetchuser = require('../middleware/fetchuser')
const dotenv = require('dotenv');
dotenv.config();
const secret=process.env.YOUR_SECRET
router.post('/login', [
body('email', 'Enter a valid Email').isEmail(),
body('password', 'Password cannot be blank').exists()
], async (req, res) => {
let success=false;
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
const { email, password } = req.body;
try {
// check whether user with this email exist
let user = await User.findOne({ email });
if (!user) {
return res.status(400).json({success, error: "Please login using correct credentials" })
};
let passwordCompare = bcrypt.compare(password, user.password);
if (!passwordCompare) {
return res.status(400).json({success, error: "Please login using correct credentials" })
};
const data = {
user: {
id: user.id
}
}
var authtoken = jwt.sign(data, secret);
success=true;
res.json({success, authtoken })
} catch (error) {
console.log(error.message);
res.status(500).send("Internal server error has occured")
}
})
you need to wait for the promise to resolve, you can opt for any of the below options
const passwordCompare = await bcrypt.compare(password, user.password);
OR
const passwordCompare = bcrypt.compareSync(password, user.password);
OR
bcrypt.compare(password, user.password).then(function(result) {
// result == true
});
I'm trying to implement JWT authentication, and I can't figure out why in Postman protected-route is available, while in my browser protected-route is Unauthorized.
I'm a beginner and its first time implementing jwt authentication in my project following this tutorial https://www.youtube.com/playlist?list=PLYQSCk-qyTW2ewJ05f_GKHtTIzjynDgjK
Problem
/login and /register work fine and I can see from the log they issue a JWT token in the req.headers
like 'Authorization':'Bearer <token>', however when I try to access GET /protected-route in my browser, it returns Unauthorized, and I can see no logging from JWTStrategy.
I think req.headers.Authorization is not set to all HTTP requests in the app, but only to POST /login, /register routes So my questions are:
Is this req.headers["Authorization"] = 'Bearer <toekn>'; correct way to set req headers to all GET and POST request in the app?
Does the jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken() checks for Authorization property in req.headers or res.headers?
I have provided the relevant code snippets please have a look!
Code:
app.js
//...
require('./config/database'); // require the db
// ...
const passport = require('passport');
const strategy = require('./config/passport').strategy;
// ...
app.use(passport.initialize());
passport.use(strategy);
// ...
module.exports = app
router/index.js
const router = express.Router();
//...
const User = require('../config/database').User;
const passport = require('passport');
const utils = require('../lib/utils');
// register route
router.post('/register', function(req, res, next){
const saltHash = utils.genPassword(req.body.password);
console.log("req.body.password is: " + req.body.password)
const salt = saltHash.salt;
const hash = saltHash.hash;
const newUser = new User({
username: req.body.username,
hash: hash,
salt: salt
})
newUser.save()
.then((user) => {
const jwt = utils.issueJWT(user);
if (jwt){
req.headers["Authorization"] = jwt.token;
}
res.redirect('/login')
})
.catch(err => next(err))
});
// login route
router.post('/login', function(req, res, next){
User.findOne({username: req.body.username})
.then((user) => {
if(!user) {
res.status(401).json({success: false, msg: "Could not find user "})
}
// validate the user
const isValid = utils.validPassword(req.body.password, user.hash, user.salt)
if(isValid) {
// issue a JWT
const jwt = utils.issueJWT(user);
if (jwt){
req.headers["Authorization"] = jwt.token;
}
res.redirect("/")
} else {
res.status(401).json({success: false, msg: "you entered the wrong password"})
}
})
.catch(err => next(err))
});
// GET protected route
router.get("/protectd-route", passport.authenticate('jwt', {session: false}), async (req, res, next) => {
res.render("user/getuser.pug")
next()
})
passport.js
const User = require('../config/database').User;
// ...
const Strategy = require('passport-jwt').Strategy;
const ExtractJwt = require('passport-jwt').ExtractJwt;
/// PUB_KEY
const pathToKey = path.join(__dirname, '..', 'id_rsa_pub.pem');
const PUB_KEY = fs.readFileSync(pathToKey, 'utf8');
// options
const options = {
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: PUB_KEY,
algorithms: ['RS256']
};
// strategy
const strategy = new Strategy(options, (payload, done) => {
User.findOne({_id: payload.sub})
.then((user) => {
if(user) {
return done(null, user)
} else {
return done(null, false)
}
})
.catch((err) => done(err, null))
});
module.exports.strategy = strategy;
utils.js
genPassword() - Creating a salt and hash out of it to store in db
validPassword() - re-hashing user salt and hash to verify
issueJWT() - signing user with jsonwebtoken
const crypto = require('crypto');
const jsonwebtoken = require('jsonwebtoken');
const User = require('../config/database').User;
//...
const pathToKey = path.join(__dirname, '..', 'id_rsa_priv.pem');
const PRIV_KEY = fs.readFileSync(pathToKey, 'utf8');
// validate in /login
function validPassword(password, hash, salt) {
var hashVerify = crypto.pbkdf2Sync(password, salt, 10000, 64, 'sha512').toString('hex');
return hash === hashVerify;
}
// generate in /register
function genPassword(password) {
var salt = crypto.randomBytes(32).toString('hex');
var genHash = crypto.pbkdf2Sync(password, salt, 10000, 64, 'sha512').toString('hex');
return {
salt: salt,
hash: genHash
};
}
// sign
function issueJWT(user) {
const _id = user._id;
const expiresIn = '86400';
const payload = {
sub: _id,
iat: Date.now()
};
const signedToken = jsonwebtoken.sign(payload, PRIV_KEY, { expiresIn: expiresIn, algorithm: 'RS256' });
return {
token: "Bearer " + signedToken,
expires: expiresIn
}
}
module.exports.validPassword = validPassword;
module.exports.genPassword = genPassword;
module.exports.issueJWT = issueJWT;
Postman
In Postman, the protected route is showing successfully, with Headers set as above.
The browser network is showing this, there is no Authorization property both in response and request headers
Clearly, I'm missing something, but I can't figure it out. Any help is appreciated
here is also my db
database.js
const uri = process.env.MONGO_URI
const connection = mongoose.connection;
mongoose.connect(uri, {
useUnifiedTopology: true,
serverSelectionTimeoutMS: 5000
})
connection.on('error', console.error.bind(console, "connection error"))
connection.once('open', () => {
console.log('MongoDB database connection has been established successfully')
})
const userSchema = new mongoose.Schema({
username: String,
hash: String,
salt: String
});
const User = mongoose.model('User', userSchema )
module.exports.User = User;
I am trying to show the page only if the Jsonwebtoken is verified and the user is logged on to the website, else show him the sign-in page.
However, I can see the token is generated in MongoDB, and also when I console log I can see that it is all good. But the issue is when I try to verify it using an already generated jwt token i.e.
req.cookies.signinToken
it shows an error.
Please the detail code below:
On app.js
const dotenv = require("dotenv");
const mongoose = require("mongoose");
const express = require("express");
const app = express();
const jwt = require("jsonwebtoken");
const cookieParser = require("cookie-parser");
dotenv.config({ path: "./config.env" });
require("./db/connection");
app.use(express.json());
app.use(cookieParser());
app.use(require("./router/route"));
const PORT = process.env.PORT;
app.listen(5000, () => {
console.log(`server running on ${PORT}`);
});
On route.js
const express = require("express");
const bcrypt = require("bcrypt");
const router = express.Router();
const jwt = require("jsonwebtoken");
require("../db/connection");
const User = require("../model/newUserSchema");
const auth = require("../middleware/auth");
// router.get("/", (req, res) => {
// res.send("hello am backend sever");
// });
//Signup or Register Part
router.post("/signup", async (req, res) => {
const { username, email, cpassword, retypePassword } = req.body;
if (!username || !email || !cpassword || !retypePassword) {
return res.status(422).json({ error: "please enter valid details" });
}
try {
const UserExist = await User.findOne({ email: email });
if (UserExist) {
return res.status(422).json({ error: "email already exist" });
} else if (cpassword !== retypePassword) {
return res.status(422).json({ error: "password incorrect" });
} else {
const user = new User({
username,
email,
cpassword,
retypePassword,
});
const userResgister = await user.save();
if (userResgister) {
return res.status(201).json({ message: "signup successfully" });
}
}
} catch (error) {
console.log(error);
}
});
//Login Part
router.post("/signin", async (req, res) => {
try {
const { email, cpassword } = req.body;
if (!email || !cpassword) {
return res.status(400).json({ error: " please enter valid credentials" });
}
const userLogin = await User.findOne({ email: email });
const token = userLogin.generateAuthToken();
res.cookie("signinToken", token, {
expires: new Date(Date.now() + 25892000000),
httpOnly: true,
});
if (userLogin) {
const isMatch = await bcrypt.compare(cpassword, userLogin.cpassword);
if (isMatch) {
return res.status(200).json({ message: "sigin in scuccessfully" });
} else {
return res.status(400).json({ error: " Invalid credentials" });
}
} else {
return res.status(400).json({ error: " Invalid credentials " });
}
} catch (error) {
console.log(error);
}
});
//watchlistpage
router.get("/watchlist", auth, (req, res) => {
console.log(" this is jwt token test " + req.cookies.signinToken);
res.send(req.rootuser);
console.log(req.rootuser);
});
module.exports = router;
On newUserSchema.js:
const mongoose = require("mongoose");
const bcrypt = require("bcrypt");
const jwt = require("jsonwebtoken");
const newUserSchema = new mongoose.Schema({
username: {
type: String,
required: true,
},
email: {
type: String,
required: true,
},
cpassword: {
type: String,
required: true,
},
retypePassword: {
type: String,
required: true,
},
tokens: [
{
token: {
type: String,
required: true,
},
},
],
});
newUserSchema.pre("save", async function (next) {
if (this.isModified("cpassword")) {
this.cpassword = await bcrypt.hash(this.cpassword, 12);
this.retypePassword = await bcrypt.hash(this.retypePassword, 12);
}
next();
});
newUserSchema.methods.generateAuthToken = async function () {
try {
let token = jwt.sign({ _id: this._id }, process.env.SECRETKEY);
this.tokens = this.tokens.concat({ token: token });
await this.save();
return token;
} catch (error) {
console.log(error);
}
};
const User = mongoose.model("newUser", newUserSchema);
module.exports = User;
On auth.js (this is also my middleware)
const jwt = require("jsonwebtoken");
const User = require("../model/newUserSchema");
const Auth = async (req, res, next) => {
try {
console.log(JSON.stringify(req.cookies.signinToken) + " this is jwt token test");
const token = req.cookies.signinToken;
const verifytoken = jwt.verify(token, process.env.SECRETKEY);
const rootuser = await User.findOne({ _id: verifytoken._id, "tokens.token": token });
if (!rootuser) {
throw new Error("user not found");
}
req.token = token;
req.rootuser = rootuser;
req.UserID = rootuser._id;
next();
} catch (error) {
res.status(401).send("Unauthorized access");
console.log(error);
}
};
module.exports = Auth;
The API call result in postman
The terminal error :
when I try to console log on route.js inside Signin page i see promise pending
const token = userLogin.generateAuthToken();
console.log(token);
res.cookie("signinToken", token, {
expires: new Date(Date.now() + 25892000000),
httpOnly: true,
});
Could you please help to correct the error also please let me know why is this error coming?
Thanks a million in advance for any tips or suggestions.
Hi Thanks for the help
I just saw that my token was returning a promise, I did not add the keyword await before the token other thing was I was trying to access it before the validation, hence it was showing me nodata and error.
Please see the correct code below:
//Login Part
router.post("/signin", async (req, res) => {
try {
const { email, cpassword } = req.body;
if (!email || !cpassword) {
return res.status(400).json({ error: " please enter valid credentials" });
}
const userLogin = await User.findOne({ email: email });
if (userLogin) {
const isMatch = await bcrypt.compare(cpassword, userLogin.cpassword);
const token = await userLogin.generateAuthToken();
console.log(token);
res.cookie("signinToken", token, {
expires: new Date(Date.now() + 25892000000),
httpOnly: true,
});
if (isMatch) {
return res.status(200).json({ message: "sigin in scuccessfully" });
} else {
return res.status(400).json({ error: " Invalid credentials" });
}
} else {
return res.status(400).json({ error: " Invalid credentials " });
}
} catch (error) {
console.log(error);
}
});
I hope this might help other learners too.
Thanks.
Trying to create a login authentication system as an entry into web development but the fetch I have to access my login functionality doesn't work. Morgan shows "POST -- ms --". (Works through Postman). As far as I can see my cors system is set up as expected. The API will respond if the passport.authenticate('local') is removed.
authenticate.js
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var User = require('./models/user');
var JwtStrategy = require('passport-jwt').Strategy;
var ExtractJwt = require('passport-jwt').ExtractJwt;
var jwt = require('jsonwebtoken'); // used to create, sign, and verify tokens
var config = require('./config.js');
exports.local = passport.use(new LocalStrategy(User.authenticate()));
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
exports.getToken = function(user) {
return jwt.sign(user, config.secretKey,
{expiresIn: 3600});
};
var opts = {};
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
opts.secretOrKey = config.secretKey;
exports.jwtPassport = passport.use(new JwtStrategy(opts,
(jwt_payload, done) => {
console.log("JWT payload: ", jwt_payload);
User.findOne({_id: jwt_payload._id}, (err, user) => {
if (err) {
return done(err, false);
}
else if (user) {
return done(null, user);
}
else {
return done(null, false);
}
});
}));
routes
var express = require('express');
var UserRouter = express.Router();
var passport = require('passport');
var User = require('../models/user')
var authenticate = require('../authenticate');
const cors = require('./cors');
const bodyParser = require('body-parser');
UserRouter.use(bodyParser.json());
UserRouter.route('/login')
.options(cors.corsWithOptions, (req, res) => { res.sendStatus(200); })
.post(cors.cors, passport.authenticate('local'), (req, res) => {
console.log(req.body);
var token = authenticate.getToken({_id: req.user._id});
res.setHeader('Content-Type', 'application/json');
res.json({success: true, token: token, status: 'You are successfully logged in!'});
res.status(200).send()
});
module.exports = UserRouter;
mongoose schema file
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var passportLocalMongoose = require('passport-local-mongoose');
var User = new Schema ({
firstname : {
type: String,
default: ""
},
lastname: {
type: String,
default: ''
},
admin: {
type: Boolean,
default: false
}
});
User.plugin(passportLocalMongoose);
module.exports = mongoose.model('User', User);
cors file
const express = require('express');
const cors = require('cors');
var whitelist = ['http://localhost:3000', 'http://localhost:3443']
var corsOptionsDelegate = (req, callback) => {
var corsOptions;
console.log("Validating origin");
console.log(req.header('Origin'));
if(whitelist.indexOf(req.header('Origin')) !== -1) {
corsOptions = { origin: true };
}
else {
corsOptions = { origin: false };
}
callback(null, corsOptions);
};
exports.cors = cors();
exports.corsWithOptions = cors(corsOptionsDelegate);
Front end API call
export const loginUser = (creds) => (dispatch) => {
console.log("test")
dispatch(requestLogin(creds))
console.log("attempting login")
return fetch('http://localhost:3443/users/login', {
method: 'POST',
headers: {
'Content-Type':'application/json',
},
body: JSON.stringify(creds)
})
.then(response => {
console.log("got response 1");
if(response.ok) {
return response
} else {
console.log("response errored");
var error = new Error('Error ' + response.status + ': ' + response.statusText);
error.response = response;
throw error;
}
},
error => {
console.log("errored")
throw error;
})
.then(response => response.json())
.then(response => {
console.log("got response 2");
if(response.success) {
// Successful login
localStorage.setItem('token', response.token);
localStorage.setItem('creds', JSON.stringify(creds));
// TODO dispatch success
dispatch(receiveLogin(response));
} else {
var error = new Error('Error ' + response.status);
error.response = response;
throw error;
}
})
.catch(error => dispatch(loginError(error.message)))
}
Does anyone know where I'm going wrong with this? I'm not really getting any useful error messages from my front-end so haven't included.
Terminal output upon login attempt
OPTIONS /users/login 204 3.287 ms - 0
POST /users/login - - ms - -
I am setting up Passport with Node/Express app (with MongoDB). For some reason I am unable to POST to /login. Strangely, the BasicStrategy instance I've set up isn't even running at all.
When I run it in Postman, I get the html file back. When I try it in the browser, for some reason I get a 200 response with the failureRedirect.
The strangest thing is that the strategy is not being called at all; the terminal console doesn't log any of the console.logs that I have set up whatsoever.
Any help would be highly appreciated. Thank you.
Here is my login router:
/users/routes/loginRouter.js
const {BasicStrategy} = require('passport-http'),
express = require('express'),
jsonParser = require('body-parser').json(),
passport = require('passport');
const {User} = require('../models');
const loginRouter = express.Router();
loginRouter.use(jsonParser);
const strategy = new BasicStrategy(function(username, password, callback) {
console.log(arguments);
let user;
User
.findOne({username: username})
.exec()
.then(_user => {
console.log(_user);
user = _user;
if (!user) {
return callback(null, false, {message: 'Incorrect username'});
}
return user.validatePassword(password);
})
.then(isValid => {
console.log(isValid);
if (!isValid) {
return callback(null, false, {messsage: 'Incorrect password'});
}
else {
return callback(null, user)
}
});
});
passport.use(strategy);
loginRouter.use(passport.initialize());
loginRouter.post('/',
passport.authenticate('basic',
{
session: true,
successRedirect: '/console',
failureRedirect: '/login'
}
)
);
module.exports = {loginRouter};
Now this is my server file:
/server.js
const express = require('express'),
bodyParser = require('body-parser'),
mongoose = require('mongoose'),
passport = require('passport');
const {adminRouter} = require('./users/routes/adminRouter'),
{loginRouter} = require('./users/routes/loginRouter'),
{registerRouter} = require('./users/routes/registerRouter'),
{PORT, DATABASE_URL} = require('./config'),
{router} = require('./router');
const app = express();
const path = require('path');
mongoose.Promise = global.Promise;
app.use(bodyParser.json());
app.use(express.static('public'));
app.use(passport.initialize());
app.use(passport.session());
app.use('/api/users/', registerRouter);
app.use('/login', loginRouter);
app.use('/console', adminRouter);
app.use('/', router);
app.get(['/login', '/register', '/about', '/archive', '/maxim/:maximId', '/console'], (req, res) => {
res.sendFile(path.resolve(__dirname, 'public', 'index.html'))});
function runServer(databaseUrl=DATABASE_URL, port=PORT) {
return new Promise((resolve, reject) => {
mongoose.connect(databaseUrl, err => {
if (err) {
return reject(err);
}
server = app.listen(port, () => {
console.log(`Your app is listening on port ${port}`);
resolve();
})
.on('error', err => {
mongoose.disconnect();
reject(err);
});
});
});
}
function closeServer() {
return mongoose.disconnect().then(() => {
return new Promise((resolve, reject) => {
console.log('Closing server');
server.close(err => {
if (err) {
return reject(err);
}
resolve();
});
});
});
}
if (require.main === module) {
runServer().catch(err => console.error(err));
};
module.exports = {app, runServer, closeServer};
My other routes are working perfectly fine, for example this register route is functioning as expected:
/users/routes/registerRouter.js
const {BasicStrategy} = require('passport-http'),
express = require('express'),
jsonParser = require('body-parser').json(),
passport = require('passport');
const {User} = require('../models');
const registerRouter = express.Router();
registerRouter.use(jsonParser);
const strategy = new BasicStrategy(
(username, password, cb) => {
User
.findOne({username})
.exec()
.then(user => {
if (!user) {
return cb(null, false, {
message: 'No such user'
});
}
if (user.password !== password) {
return cb(null, false, 'Incorrect password');
}
return cb(null, user);
})
.catch(err => cb(err))
});
passport.use(strategy);
registerRouter.post('/', (req, res) => {
if (!req.body) {
return res.status(400).json({message: 'No request body'});
}
if (!('username' in req.body)) {
return res.status(422).json({message: 'No username in request body'});
}
let {username, password, email} = req.body;
if (typeof username !== 'string') {
return res.status(422).json({message: 'Incorrect field type: username'});
}
username = username.trim();
if (username === '') {
return res.status(422).json({message: 'Incorrect field length: username'});
}
if (!(password)) {
return res.status(422).json({message: 'No password in request body'});
}
if (typeof password !== 'string') {
return res.status(422).json({message: 'Incorrect field type: password'});
}
password = password.trim();
if (password === '') {
return res.status(422).json({message: 'Incorrect field length: password'});
}
if (typeof email !== 'string') {
return res.status(422).json({message: 'Incorrect field type: email'});
}
email = email.trim();
if (email === '') {
return res.status(422).json({message: 'Incorrect field length: email'});
}
// check for existing user
return User
.find({username})
.count()
.exec()
.then(count => {
if (count > 0) {
return res.status(422).json({message: 'Username taken'});
}
// if no existing user, hash password
return User.hashPassword(password)
})
.then(hash => {
return User
.create({
username: username,
password: hash,
email: email
})
})
.then(user => {
return res.status(201).json(user.apiRep());
})
.catch(err => {
res.status(500).json({message: 'Internal Server Error'})
});
});
module.exports = {registerRouter};