Skip to content

Commit

Permalink
feat: Add user authentication (#71)
Browse files Browse the repository at this point in the history
Add jsonwebtokens and bcrypt packages as dependencies for the app. Add
routes needed to authenticate and authorize user.

Minor refactor to savedPins docstrings and status codes.
  • Loading branch information
jkwening authored and motosharpley committed Feb 2, 2018
1 parent 39694c6 commit ab633ff
Show file tree
Hide file tree
Showing 9 changed files with 309 additions and 42 deletions.
1 change: 1 addition & 0 deletions config/dev.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ module.exports = {
PORT: process.env.PORT || 8081,
DB_URL: SECRETS.mongodb_dev.db_url,
GOOGLE_API_KEY: SECRETS.google_maps.api_key,
JWT_KEY: SECRETS.jwt.key,
};
1 change: 1 addition & 0 deletions config/prod.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ module.exports = {
PORT: process.env.PORT,
DB_URL: SECRETS.mongodb_prod.db_url,
GOOGLE_API_KEY: SECRETS.google_maps.api_key,
JWT_KEY: SECRETS.jwt.key,
};
5 changes: 5 additions & 0 deletions config/secrets-example.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@
"db_url": ""
},

"jwt": {
"_comment": "Private key with passphrase object to be used for generating tokens",
"key": "passphrase"
},

"other_secret_type": {
"_comment": "Any API keys or other password-type strings can be stored like this.",
"specific_secret_component":"component",
Expand Down
33 changes: 14 additions & 19 deletions controllers/saved-pins-controller.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,30 @@
const SavedPins = require('../models/saved-pins');

/**
* TODO - export functions to be used for completing requests in ../routes/search.js
*/

/**
* Function to GET saved pins from the SavedPins model
* @api {GET} /savedpins Request SavedPins information
* @apiSuccess 200 {SavedPins} returns a collection of SavedPins.
* @apiError 400 returns {error}
* @description Handles request for user saved pins
*
* @param {any} appReq
* @param {any} appRes
* @api {GET} /savedpins
* @apiSuccess 200 {SavedPins} The collection of saved pins.
* @apiError 500 {server error} Problem finding all saved pins.
*/
exports.getSavedPins = (appReq, appRes) => {
SavedPins.find().then((savedPins) => {
appRes.send({ savedPins });
}, (e) => {
appRes.status(400).send(e);
appRes.status(500).send(e);
});
};

/**
* Function to POST saved pins from the SavedPins model
* @api {POST} /savedpins saves {SavedPins}
* @apiSuccess 200 {SavedPins} returns the mongodb {SavedPins} after saved.
* @apiError 400 returns {error}
* @description Handles request to save a pin
*
* @param {any} appReq
* @param {any} appRes
* @api {POST} /savedpins
* @apiSuccess 200 {SavedPins} The document representing the saved pin.
* @apiError 500 {server error} Problem saving the requested pin.
*
* @param {number} appReq.body.lat - lattitude coordinate for pin location
* @param {number} appReq.body.lng - longitude coordinate for pin location
* @param {string} appReq.body.place_id - name of pin location
*/
exports.postSavedPins = (appReq, appRes) => {
const savedPin = new SavedPins({
Expand All @@ -40,7 +36,6 @@ exports.postSavedPins = (appReq, appRes) => {
savedPin.save().then((pin) => {
appRes.send(pin);
}, (e) => {
appRes.status(400).send(e);
appRes.status(500).send(e);
});
};

134 changes: 132 additions & 2 deletions controllers/users-controller.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,135 @@
const SearchHistory = require('../models/users');
const User = require('../models/users');
const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs');
const {JWT_KEY} = require('../config');

/**
* TODO - export functions to be used for completing requests in ../routes/users.js
* @description Handles user registeration
*
* @api {POST} /register
* @apiSuccess 200 {auth: true, token: token} jsonwebtoken.
* @apiError 409 {request error} Email already exists.
* @apiError 500 {server error} Registeration failed.
*
* @param {string} appReq.body.name - name provided by user
* @param {string} appReq.body.email - email provided by user
* @param {string} appReq.body.password - user provided password
*/
exports.registerUser = (appReq, appRes) => {
// check whether user already exists with given email
User.count({ email: appReq.body.email }, (err, result) => {
if (err) {
return appRes.status(500)
.send('There was a problem registering the user.');
}
if (result > 0) return appRes.status(409).send('Email already in use.');
});

/**
* TODO
* 1. validate to ensure null values are passed for name,
* email, or password.
* 2. verify email is valid i.e. '....'@'...'.'...'
* 3. validate for secure passwords and no easy to guess passwords
*/

// encrypt password
const HASHED_PASSWORD = bcrypt.hashSync(appReq.body.password, 8);

User.create(
{
name: appReq.body.name,
email: appReq.body.email,
password: HASHED_PASSWORD,
},
(err, user) => {
if (err) {
return appRes.status(500)
.send('There was a problem registering the user.');
}

// create token
const token = jwt.sign({ id: user._id }, JWT_KEY, {
expiresIn: 86400, // expires in 24 hours
});

appRes.status(200).send({ auth: true, token });
},
);
};

/**
* @description Get users information by utilizing verifyToken to
* authenticate user informtion.
*
* @api {GET} /user
* @apiSuccess 200 {_id: db._id, name: user_name, email: user_email} User info.
* @apiError 400 {request error} User not found.
* @apiError 500 {server error} Problem finding user.
*/
exports.getUser = (appReq, appRes) => {
User.findById(
appReq.userId,
{ password: 0 },
(err, user) => {
if (err) return appRes.status(500).send('There was a problem with finding the user.');

if (!user) return appRes.status(400).send('No user found.');

appRes.status(200).send(user);
},
);
};

/**
* @description Handles user login
*
* @api {POST} /login
* @apiSuccess 200 {auth: true, token: token} jsonwebtoken.
* @apiError 400 {request error} User not found.
* @apiError 401 {auth: false, token: null} Invalid password.
* @apiError 500 {server error} Problem finding user.
*
* @param {string} appReq.body.email - email provided by user
* @param {string} appReq.body.password - user provided password
*/
exports.loginUser = (appReq, appRes) => {
User.findOne({ email: appReq.body.email }, (err, user) => {
if (err) return appRes.status(500).send('Error on the server.');
if (!user) return appRes.status(404).send('No user found.');

const passwordIsValid = bcrypt.compareSync(
appReq.body.password,
user.password,
);

if (!passwordIsValid) {
return appRes.status(401).send({
auth: false,
token: null,
});
}

const token = jwt.sign({ id: user._id }, JWT_KEY, {
expiresIn: 86400,
});

appRes.status(200).send({
auth: true,
token,
});
});
};

/**
* @description Handles logout request for backend testing purposes.
* NOTE - frontend should handle user logout by deleting cached token
*
* @api {GET} /logout
*/
exports.logoutUser = (appReq, appRes) => {
appRes.status(200).send({
auth: false,
token: null,
});
};
5 changes: 3 additions & 2 deletions models/users.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
const mongoose = require('mongoose');

const Schema = mongoose.Schema;
const usersSchema = new Schema({
const usersSchema = new mongoose.Schema({
name: { type: String, required: true },
email: { type: String, required: true },
password: { type: String, required: true },
});

module.exports = mongoose.model('Users', usersSchema);
109 changes: 109 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit ab633ff

Please sign in to comment.