Jucundus/backend/routes/auth.js

113 lines
3.9 KiB
JavaScript

var passport = require('passport');
var LocalStrategy = require('passport-local');
var crypto = require('crypto');
const router = require('express').Router()
const config = require("../config.js");
const keys = require("../.Keys.js");
/* Configure password authentication strategy.
*
* The `LocalStrategy` authenticates users by verifying a username and password.
* The strategy parses the username and password from the request and calls the
* `verify` function.
*
* The `verify` function queries the database for the user record and verifies
* the password by hashing the password supplied by the user and comparing it to
* the hashed password stored in the database. If the comparison succeeds, the
* user is authenticated; otherwise, not.
*/
const { UserDb }= require('../services/userDb');
passport.use(new LocalStrategy({
usernameField: 'email',
passwordField: 'password'
},async function verify(email, password, cb) {
try {
const userDb = await UserDb.init();
const user = await userDb.getByEmail(email);
if (!user) {
return cb(null, false, { message: 'Incorrect username or password.' });
}
crypto.pbkdf2(password, user.salt, 310000, 32, 'sha256', async function(err, hashedPassword) {
if (err) { return cb(err); }
if (!crypto.timingSafeEqual(Buffer.from(user.hashed_password, 'hex'), Buffer.from(hashedPassword, 'hex'))) {
return cb(null, false, { message: 'Incorrect username or password.' });
}
return cb(null, user);
});
} catch (err) {
return cb(err);
}
}));
/* Configure session management.
*
* When a login session is established, information about the user will be
* stored in the session. This information is supplied by the `serializeUser`
* function, which is yielding the user ID and username.
*
* As the user interacts with the app, subsequent requests will be authenticated
* by verifying the session. The same user information that was serialized at
* session establishment will be restored when the session is authenticated by
* the `deserializeUser` function.
*
* Since every request to the app needs the user ID and username, in order to
* fetch todo records and render the user element in the navigation bar, that
* information is stored in the session.
*/
passport.serializeUser(function(user, cb) {
process.nextTick(function() {
cb(null, { id: user._id, username: user.email });
});
});
passport.deserializeUser(function(user, cb) {
process.nextTick(function() {
return cb(null, user);
});
});
// JWT
var jwt = require('jsonwebtoken');
var JwtStrategy = require('passport-jwt').Strategy,
ExtractJwt = require('passport-jwt').ExtractJwt;
var opts = {}
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
opts.secretOrKey = keys.jwt;
opts.issuer = config.jwtOptions.issuer;
opts.audience = config.jwtOptions.audience;
passport.use(new JwtStrategy(opts, async function(jwt_payload, done) {
const userDb = await UserDb.init();
try {
const user = await userDb.get(jwt_payload.sub);
if (user) {
return done(null, user);
} else {
return done(null, false);
// or you could create a new account
}
} catch (err) {
return done(err, false);
}
}));
router.post('/authenticate', async function(req, res) {
passport.authenticate('local', async function(err, user, info) {
if (err) { return res.status(500).json({message: err.message}); }
if (!user) { return res.status(401).json({message: 'Incorrect email or password.'}); }
// User found, generate a JWT for the user
var token = jwt.sign({ sub: user._id, email: user.email }, opts.secretOrKey, {
issuer: opts.issuer,
audience: opts.audience,
expiresIn: 86400 * 30 // 30 days
});
res.json({ token: token });
//return res.status(500).json({message: 'Incorrect email or password.'})
})(req, res);
});
module.exports = router;