Auth with Passport - kplian/pxp-nd GitHub Wiki
Passport
Passport is Express-compatible authentication middleware for Node.js. Passport's sole purpose is to authenticate requests, which it does through an extensible set of plugins known as strategies. Passport does not mount routes or assume any particular database schema, which maximizes flexibility and allows application-level decisions to be made by the developer. For more information visit the official Passport website.
How use Passport?
Install
$ npm install passport
Passport initialization should be done in your main app file. But previously, an authentication strategy must be configured. Below is the configuration for a Local authentication.
Passport Strategy Local
Passport uses what are termed strategies to authenticate requests. Strategies range from verifying a username and password. Strategies, and their configuration, are supplied via the use() function.
1. Install passport Local
$ npm install passport-local
2. Configure Passport Local Strategy
Create a file config src/lib/auth/passport-local.js, a complete example configuration is shown below:
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
// Object for connect to database, this example using postgresSql
const pool = require('../PgPool');
// function for valid user password
const validPassword = require('./passwordUtils').validPassword;
// Params for login method
const customFields = {
usernameField: 'username',
passwordField: 'password'
};
// This method is used to verify the user's data, it determines if the user is valid.
const verifyCallback = (username, password, done) => {
pool.query('select * from pxp."user1" where username=$1', [username])
.then(({ rows }) => {
const user = rows[0];
if (!user) { return done(null, false) }
const isValid = validPassword(password, user.hash, user.salt);
if (isValid) {
return done(null, user);
} else {
return done(null, false);
}
})
.catch((err) => {
done(err);
});
}
// Define strategy Passport Local
const strategy = new LocalStrategy(customFields, verifyCallback);
passport.use(strategy);
// This method is used to store the user identifier locally.
passport.serializeUser((user, done) => {
done(null, user.id);
});
// This method is used to extract user data.
passport.deserializeUser((userId, done) => {
pool.query('select * from pxp."user1" where id=$1', [userId])
.then(({ rows }) => {
const user = rows[0];
done(null, user);
})
.catch(err => done(err))
});
Create file src/lib/auth/passwordUtils.js, this file contents methods for valid and generate password using the library crypto.
Should install previos crypio $ npm install crypto:
const crypto = require('crypto');
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
};
}
function validPassword(password, hash, salt) {
var hashVerify = crypto.pbkdf2Sync(password, salt, 10000, 64, 'sha512').toString('hex');
return hash === hashVerify;
}
module.exports.validPassword = validPassword;
module.exports.genPassword = genPassword;
3. Define auth routes
For example create file src/lib/auth/authRoutes.js, set the following routes:
const { Router } = require('express');
const router = Router();
const passport = require('passport');
const { validPassword } = require('./passwordUtils');
// endPoint for register user
router.post('/api/register', (req, res, next)=>{ //callback for register user });
// endPoint for login user, using localStrategy
router.post('/api/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
console.log(err, user, info)
if (err) { return next(err); }
if (!user) { return res.status(400).send({ message: 'Invalid username or password'}); }
req.logIn(user, function(err) {
if (err) { return next(err); }
// custom response for user login valid
return res.status(200).send(user);
});
})(req, res, next);
});
// endPoint for logout auth user, this method is shared with others passport strategies
router.get('/api/logout', (req, res, next) => {
req.logout();
res.status(200).send({
message: 'Logout correct'
});
});
4. Configure passport
Finally import config file passport and auth routes in your main app file;
/*** PASSPORT CONFIG */
const passport = require('passport');
const session = require('express-session');
const authRoutes = require('./src/lib/auth/authRoutes');
// ...
/*-------------- PASSPORT SETUP ----------------*/
require('./src/lib/auth/passport-local'); // your config local strategy
app.use(passport.initialize()); // initialize passport
// Passport will inject the user object in all its routes if it is logged in.
app.use((req, res, next) => {
console.log(req.user);
next();
});
Now you can test the configured routes.