server/api/auth/auth.api.js

/**
 * Authentication API.
 *
 * @module server/api/auth
 */
const _ = require('lodash');
const moment = require('moment');

const config = require('../../../config');
const User = require('../../models/user');
const usersPolicy = require('../users/users.policy');
const { route } = require('../utils/api');
const errors = require('../utils/errors');
const { validateRequestBody } = require('../utils/validation');

// API resource name (used in some API errors).
exports.resourceName = 'auth';

const logger = config.logger(`api:${exports.resourceName}`);

/**
 * **POST /api/auth**
 *
 * Creates a new, short-lived (2 weeks) authentication token for a user.
 * The correct e-mail and password must be provided.
 *
 * @function
 */
exports.authenticate = route(async function(req, res) {

  await validateAuthentication(req);

  // Load the user by e-mail.
  const email = _.get(req, 'body.email', '_').toString();
  const user = await new User({ email: email.toLowerCase() }).fetch();
  if (!user || !user.isActive()) {
    throw errors.unauthorized('auth.invalidUser', 'This user account does not exist or is inactive.');
  }

  // Check the password.
  const password = req.body.password;
  if (!_.isString(password) || !user.hasPassword(password)) {
    throw errors.unauthorized('auth.invalidCredentials', 'The password is invalid.');
  }

  req.currentUser = user;
  logger.info(`User ${user.get('api_id')} has logged in`);

  // Return a new JWT and the user.
  res.status(201).json({
    token: user.generateJwt({
      exp: moment().add(2, 'weeks').unix()
    }),
    user: usersPolicy.serialize(req, user)
  });
});

function validateAuthentication(req) {
  return validateRequestBody(req, function() {
    return this.parallel(
      this.validate(
        this.json('/email'),
        this.required(),
        this.type('string'),
        this.email()
      ),
      this.validate(
        this.json('/password'),
        this.required(),
        this.type('string'),
        this.notBlank()
      )
    );
  });
}