From b1afdaa77672f38150f9a191fa87a36743e35c09 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 22 May 2024 10:48:58 -0700 Subject: [PATCH] Added JWT to registration and login --- README.md | 39 +++++------- Server/controllers/authController.js | 27 +++++--- Server/db/FakeDb.js | 4 +- Server/package-lock.json | 94 ++++++++++++++++++++++++++++ Server/package.json | 1 + 5 files changed, 130 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 92e1b7bb1..f964a6c00 100644 --- a/README.md +++ b/README.md @@ -39,13 +39,14 @@ BlueWave uptime monitoring application Configure the server with the following environmental variables -| ENV Varialbe Name | Required/Optional | Type | Description | Accepted Values | -| -------------------- | ----------------- | ------- | ---------------------------------------------------- | ------------------- | -| DB_TYPE | Optional | string | Specify DB to use | `MongoDB \| FakeDB` | -| DB_CONNECTION_STRING | Required | string | Specfies URL for MongoDB Database | | -| PORT | Optional | Integer | Specifies Port for Server | | -| MAILERSEND_API_KEY | Required | string | Specfies API KEY for MailerSend service | | -| SYSTEM_EMAIL_ADDRESS | Required | string | Specfies System email to be used in emailing service | | +| ENV Varialbe Name | Required/Optional | Type | Description | Accepted Values | +| -------------------- | ----------------- | --------- | ---------------------------------------------------- | ------------------- | +| JWT_SECRET | Required | `string` | JWT secret | | +| DB_TYPE | Optional | `string` | Specify DB to use | `MongoDB \| FakeDB` | +| DB_CONNECTION_STRING | Required | `string` | Specfies URL for MongoDB Database | | +| PORT | Optional | `integer` | Specifies Port for Server | | +| MAILERSEND_API_KEY | Required | `string` | Specfies API KEY for MailerSend service | | +| SYSTEM_EMAIL_ADDRESS | Required | `string` | Specfies System email to be used in emailing service | | --- @@ -130,9 +131,9 @@ Example: ##### Response Payload -> | Type | Notes | -> | ------ | ---------- | -> | `User` | User model | +> | Type | Notes | +> | ---- | ---------------------------------- | +> | JWT | JSON Web Token containing a `User` | ##### Sample CURL request @@ -191,9 +192,9 @@ curl --request POST \ ##### Response Payload -> | Type | Notes | -> | ------ | ---------- | -> | `User` | User model | +> | Type | Notes | +> | ---- | ---------------------------------- | +> | JWT | JSON Web Token Containing a `User` | ##### Sample CURL request @@ -213,17 +214,7 @@ curl --request POST \ { "success": true, "msg": "Found user", - "data": { - "_id": "6644fb9bae0b439371913969", - "firstname": "User First Name", - "lastname": "User Last Name", - "email": "user@gmail.com", - "isActive": true, - "isVerified": false, - "updated_at": "2024-05-15T18:14:51.049Z", - "created_at": "2024-05-15T18:14:51.049Z", - "__v": 0 - } + "data": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2NjQ1MDc5YWFlMGI0MzkzNzE5MTM5NzIiLCJmaXJzdG5hbWUiOiJBbGV4IiwibGFzdG5hbWUiOiJIb2xsaWRheSIsImVtYWlsIjoiYWpob2xsaWRAZ21haWwuY29tIiwiaXNBY3RpdmUiOnRydWUsImlzVmVyaWZpZWQiOmZhbHNlLCJ1cGRhdGVkX2F0IjoiMjAyNC0wNS0xNVQxOTowNjowMi43MjBaIiwiY3JlYXRlZF9hdCI6IjIwMjQtMDUtMTVUMTk6MDY6MDIuNzIwWiIsIl9fdiI6MCwiaWF0IjoxNzE2Mzk5MDM2fQ.clFR01gh5XK9DtLjB-_JLxMBAzBZuduRQv3ZzqHuTRY" } ``` diff --git a/Server/controllers/authController.js b/Server/controllers/authController.js index e8fdc739e..2c0c8d755 100644 --- a/Server/controllers/authController.js +++ b/Server/controllers/authController.js @@ -1,7 +1,9 @@ const express = require("express"); -const UserModel = require("../models/user"); const { registerValidation, loginValidation } = require("../validation/joi"); const logger = require("../utils/logger"); +require("dotenv").config(); + +var jwt = require("jsonwebtoken"); /** * @function @@ -42,19 +44,25 @@ const registerController = async (req, res) => { // TODO: Send an email to user // Will add this later logger.info("New user created!", { service: "auth", userId: newUser._id }); + const token = jwt.sign(newUser, process.env.JWT_SECRET); + return res .status(200) - .json({ success: true, msg: "User created}", data: newUser }); + .json({ success: true, msg: "User created}", data: token }); } catch (error) { logger.error(error.message, { service: "auth" }); return res.status(500).json({ success: false, msg: error.message }); } }; -// ************************** -// Handles logging in a user -// Returns a user at the moment, but will likely return a JWT in the future -// ************************** +/** + * Returns JWT with User info + * @async + * @param {Express.Request} req + * @param {Express.Response} res + * @returns {Promise} + * @throws {Error} + */ const loginController = async (req, res) => { try { // Validate input @@ -69,7 +77,6 @@ const loginController = async (req, res) => { } // Compare password const match = await user.comparePassword(req.body.password); - console.log(user); if (!match) { throw new Error("Password does not match!"); } @@ -80,11 +87,11 @@ const loginController = async (req, res) => { const userWithoutPassword = { ...user._doc }; delete userWithoutPassword.password; - // Happy path, return user - // In the future we'll probably return a JWT instead of a user + // Happy path, return token + const token = jwt.sign(userWithoutPassword, process.env.JWT_SECRET); return res .status(200) - .json({ success: true, msg: "Found user", data: userWithoutPassword }); + .json({ success: true, msg: "Found user", data: token }); } catch (error) { // Anything else should be an error logger.error(error.message, { service: "auth" }); diff --git a/Server/db/FakeDb.js b/Server/db/FakeDb.js index b2abd919e..6a65bf502 100644 --- a/Server/db/FakeDb.js +++ b/Server/db/FakeDb.js @@ -41,7 +41,9 @@ const insertUser = async (req, res) => { const salt = await bcrypt.genSalt(10); //genSalt is asynchronous, need to wait newUser.password = await bcrypt.hash(newUser.password, salt); // hash is also async, need to eitehr await or use hashSync USERS.push(newUser); - return newUser; + const userToReturn = { ...newUser._doc }; + delete userToReturn.password; + return userToReturn; } catch (error) { throw error; } diff --git a/Server/package-lock.json b/Server/package-lock.json index 495d5bc2e..9ee830ebd 100644 --- a/Server/package-lock.json +++ b/Server/package-lock.json @@ -15,6 +15,7 @@ "express": "^4.19.2", "helmet": "^7.1.0", "joi": "^17.13.1", + "jsonwebtoken": "9.0.2", "mailersend": "^2.2.0", "mongoose": "^8.3.3", "winston": "^3.13.0" @@ -310,6 +311,11 @@ "node": ">=16.20.1" } }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -535,6 +541,14 @@ "url": "https://dotenvx.com" } }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -1073,6 +1087,51 @@ "@sideway/pinpoint": "^2.0.0" } }, + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jsonwebtoken/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "node_modules/kareem": { "version": "2.6.3", "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.6.3.tgz", @@ -1086,6 +1145,41 @@ "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" + }, "node_modules/logform": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.0.tgz", diff --git a/Server/package.json b/Server/package.json index 6a082cbdc..60777f7a5 100644 --- a/Server/package.json +++ b/Server/package.json @@ -17,6 +17,7 @@ "express": "^4.19.2", "helmet": "^7.1.0", "joi": "^17.13.1", + "jsonwebtoken": "9.0.2", "mailersend": "^2.2.0", "mongoose": "^8.3.3", "winston": "^3.13.0"