/**
* @fileOverview A service that handles login and authentication on each request.
*
* @author Ralfs Lagzda
*
* @requires NPM:mongoose
* @requires NPM:jsonwebtoken
* @requires ../models/user
* @requires ../config
*/
const mongoose = require('mongoose');
const jwt = require('jsonwebtoken');
mongoose.Promise = global.Promise;
const User = require('../models/user');
const config = require('../config');
/**
* Authenticates a user based on the signed JWT token
*
* @memberOf AuthService
* @function authenticate
* @param {String} token - The signed user JWT token string
* @returns {Promise<User>} Promise that eventually authenticates
* and resolves the user or fails
*/
const authenticate = token => new Promise(async (resolve, reject) => {
if (token) {
jwt.verify(token, config.secretKey, (err, decode) => {
if (err) reject(Error({ message: 'Invalid token' }));
else resolve(decode.user);
});
} else {
reject(Error({ message: 'No token' }));
}
});
/**
* Login a user based on the credentials
*
* @memberOf AuthService
* @function login
* @param {Object} credentials - The user credential object containing username and password
* @param {string} credentials.username - The username.
* @param {string} credentials.password - The password.
* @returns {Promise<User>} Promise that eventually authenticates
* and resolves the user with JWT or fails
*/
const login = credentials => new Promise(async (resolve, reject) => {
try {
const user = await User.findOne({ username: credentials.username });
if (!await user.verifyPassword(credentials.password)) throw (Error('Invalid login'));
user.password = undefined;
const token = jwt.sign({
expiresIn: 60 * 60 * 60 * 3, // expires in 3 hours
user,
}, config.secretKey);
resolve({ token, user });
} catch (err) {
reject(err);
}
});
/**
* Authorizes access to a user or resource owned by a user
*
* @memberOf AuthService
* @function authorize
* @param {Object} authenticatedUser - The user which is currently authenticated
* @param {string} authenticatedUser.id - The id of the user.
* @param {String} userId - The user id in the path to access a resource
* @returns {Promise<Boolean>} Promise that eventually authorizes the user
* and resolves a boolean or fails
*/
const authorize = (authenticatedUser, userId) => new Promise((resolve, reject) => {
if (authenticatedUser.id === userId) resolve();
else reject(Error({ message: 'Not authorized' }));
});
/**
* A service that handles login and authentication on each request
* @namespace AuthService
*/
module.exports = {
authenticate,
authorize,
login,
};