Skip to content

Instantly share code, notes, and snippets.

@juliojgarciaperez
Last active June 8, 2019 09:50
Show Gist options
  • Save juliojgarciaperez/6b00fec184fc1a64a7368e79b12d314d to your computer and use it in GitHub Desktop.
Save juliojgarciaperez/6b00fec184fc1a64a7368e79b12d314d to your computer and use it in GitHub Desktop.
Express API auth guide

1. install packages

npm i bcrypt connect-mongo express-session passport passport-local

2. Add passport config

configs/passport.config.js

const User = require('../models/user.model');
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;


 passport.serializeUser((user, next) => {
  next(null, user.id);
});

 passport.deserializeUser((id, next) => {
  User.findById(id)
    .then(user => next(null, user))
    .catch(next)
});


passport.use('auth-local', new LocalStrategy({
  usernameField: 'email',
  passwordField: 'password'
}, (email, password, next) => {
  User.findOne({ email: email })
    .then(user => {
      if (!user) {
        next(null, false, 'Invalid email or password')
      } else {
        return user.checkPassword(password)
          .then(match => {
            if (!match) {
              next(null, false, 'Invalid email or password')
            } else {
              next(null, user)
            }
          })
      }
    })
    .catch(error => next(error))
}));

3. Add session config

configs/session.config.js

const session = require('express-session');
const MongoStore = require("connect-mongo")(session);
const mongoose = require('mongoose');

 module.exports = session({
  secret: process.env.SESSION_SECRET || 'SuperSecret - (Change it)',
  resave: false,
  saveUninitialized: true,
  cookie: {
    secure: false,
    httpOnly: true,
    maxAge: 60 * 60 * 24 * 1000
  },
  store: new MongoStore({
    mongooseConnection: mongoose.connection,
    ttl: 24 * 60 * 60
  })
}); 

4. Add User model

models/user.model.js

const mongoose = require('mongoose');
const bcrypt = require('bcrypt');
const SALT_WORK_FACTOR = 10

 const userSchema = new mongoose.Schema({
  email: {
    type: String,
    required: true,
    unique: true
  },
  password: {
    type: String,
    required: true,
    minlength: 8
  }
}, {
    timestamps: true,
    toJSON: {
      virtuals: true,
      transform: (doc, ret) => {
        ret.id = doc._id;
        delete ret._id;
        delete ret.__v;
        delete ret.password;
        return ret;
      }
    }
  })

 userSchema.pre('save', function (next) {
  const user = this;

   if (!user.isModified('password')) {
    next();
  } else {
    bcrypt.genSalt(SALT_WORK_FACTOR)
      .then(salt => {
        return bcrypt.hash(user.password, salt)
          .then(hash => {
            user.password = hash;
            next();
          })
      })
      .catch(error => next(error))
  }
});

 userSchema.methods.checkPassword = function (password) {
  return bcrypt.compare(password, this.password);
}


const User = mongoose.model('User', userSchema);

module.exports = User; 

5. Add auth routes

routes/auth.routes.js

const express = require('express');
const router = express.Router();

const secure = require('../middlewares/secure.mid');
const authController = require('../controllers/auth.controller');

 router.post('/register', authController.register);
router.post('/authenticate', authController.authenticate);
router.post('/logout', secure.isAuthenticated, authController.logout);

 module.exports = router; 

6. Add auth controller

controllers/auth.controller.js

const User = require('../models/user.model');
const createError = require('http-errors');
const passport = require('passport');

 module.exports.register = (req, res, next) => {
  const { email } = req.body;
  User.findOne({ email: email })
    .then(user => {
      if (user) {
        throw createError(409, 'Email already registered')
      } else {
        return new User(req.body).save();
      }
    })
    .then(user => res.status(201).json(user))
    .catch(next)
}

 module.exports.authenticate = (req, res, next) => {
  passport.authenticate('auth-local', (error, user, message) => {
    if (error) {
      next(error);
    } else if (!user) {
      next(createError(401, message));
    } else {
      req.login(user, (error) => {
        if (error) {
          next(error)
        } else {
          res.status(201).json(user);
        }
      })
    }
  })(req, res, next);
}

 module.exports.logout = (req, res, next) => {
  req.logout();
  res.status(204).json();
} 

7. Add secure middleware

middlewares/secure.mid.js

const createError = require('http-errors');

 module.exports.isAuthenticated = (req, res, next) => {
  if (req.isAuthenticated()) {
    next();
  } else {
    next(createError(401));
  }
} 

8. Add middleware to protected routes

routes/whatever.route.js

// ...
const secure = require('../middlewares/secure.mid');

router.get('/', secure.isAuthenticated, controller.list);

// ...

9. setup app.js

app.js

const passport = require('passport');

// ...

require('./configs/passport.config');
const session = require('./configs/session.config');

// ...

const authRouter = require('./routes/auth.routes');

// ...

app.use(session)
app.use(passport.initialize());
app.use(passport.session());


//...

app.use('/', authRouter);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment