From 54677c68f50b7c105a1f6cc5e9593877781fc8d6 Mon Sep 17 00:00:00 2001 From: Mateja Date: Sat, 10 Jul 2021 22:57:13 +0200 Subject: Implemented JWT authentication using Passport.js --- server/config/passport.js | 29 ++++++++++++++++++++++++++++ server/controllers/user.js | 47 ++++++++++++++++++++++++++++++++++++++++++++++ server/main.js | 4 ++++ server/models/User.js | 1 + server/package-lock.json | 2 +- server/package.json | 1 + server/routes/api.js | 5 +++++ 7 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 server/config/passport.js create mode 100644 server/controllers/user.js diff --git a/server/config/passport.js b/server/config/passport.js new file mode 100644 index 0000000..02ad4f6 --- /dev/null +++ b/server/config/passport.js @@ -0,0 +1,29 @@ +const passport = require('passport'); +const jwtStrategy = require('passport-jwt').Strategy; +const extractJwt = require('passport-jwt').ExtractJwt; + +const {masterKey} = require("../config/env"); +const User = require('../models/User'); + +const options = { + jwtFromRequest: extractJwt.fromAuthHeaderAsBearerToken(), + secretOrKey: masterKey +}; + +const jwtStrategyCallback = (jwtPayload, done) => { + // Try to find user + User.findOne({_id: jwtPayload.sub}, (err, user) => { + // Database error + if (err) + return done(err, false); + + // No user found + if (!user) + return done(null, false); + + // Successful login + return done(null, user); + }) +}; + +passport.use(new jwtStrategy(options, jwtStrategyCallback)); diff --git a/server/controllers/user.js b/server/controllers/user.js new file mode 100644 index 0000000..e3c1078 --- /dev/null +++ b/server/controllers/user.js @@ -0,0 +1,47 @@ +const bcrypt = require('bcryptjs'); +const jwt = require('jsonwebtoken'); + +const User = require('../models/User'); +const {masterKey} = require("../config/env"); + +module.exports = { + + register(req, res) { + if (req.body.password !== req.body.confirmPassword) + res.json({status: "Passwords do not match!"}); + else { + const newUser = new User({ + firstname: req.body.firstname, + lastname: req.body.lastname, + email: req.body.email, + password: bcrypt.hashSync(req.body.password) + }); + + newUser.save() + .then(() => res.json({status: "User successfully registered!"})) + .catch(err => res.json({ + status: "Error when registering user!", + error: err + })); + } + }, + + login(req, res) { + User.findOne({email: req.body.email}, (err, user) => { + if (err) + res.json({status: "Database error.", error: err}); + + if (!bcrypt.compareSync(req.body.password, user.password)) + res.json({status: "Wrong credentials!"}); + else { + const payload = {sub: user._id}; + const token = jwt.sign(payload, masterKey, {expiresIn: "1d"}); + res.json({ + status: "Successfully logged in!", + token + }); + } + }); + } + +}; diff --git a/server/main.js b/server/main.js index 4fbb0be..bdcf9a4 100644 --- a/server/main.js +++ b/server/main.js @@ -1,6 +1,7 @@ const express = require('express'); const app = express(); const mongoose = require('mongoose'); +const passport = require('passport'); const {port, mongoUrl} = require("./config/env"); const apiRoutes = require('./routes/api'); @@ -16,6 +17,9 @@ mongoose.connection.once('open', () => console.log("Successfully connected to Mo app.use(express.json()); +require('./config/passport'); +app.use(passport.initialize()); + app.use('/api', apiRoutes); app.listen(port, () => console.log(`Server started on port ${port}.`)); diff --git a/server/models/User.js b/server/models/User.js index 401fb32..294c016 100644 --- a/server/models/User.js +++ b/server/models/User.js @@ -22,6 +22,7 @@ const UserSchema = new mongoose.Schema({ }, email: { type: String, + unique: [true, "Account with given email already exists!"], required: [true, "You need to provide an email."], maxLength: [100, "You can't have a email longer than 100 characters."], validate: { diff --git a/server/package-lock.json b/server/package-lock.json index 6b5a9bf..1864692 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -1,6 +1,6 @@ { "name": "server", - "version": "1.0.0", + "version": "0.1.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/server/package.json b/server/package.json index 096861b..05b399e 100644 --- a/server/package.json +++ b/server/package.json @@ -13,6 +13,7 @@ "bcryptjs": "^2.4.3", "dotenv": "^10.0.0", "express": "^4.17.1", + "jsonwebtoken": "^8.5.1", "mongoose": "^5.13.2", "passport": "^0.4.1", "passport-jwt": "^4.0.0", diff --git a/server/routes/api.js b/server/routes/api.js index 3684aa0..a0890a7 100644 --- a/server/routes/api.js +++ b/server/routes/api.js @@ -1,8 +1,13 @@ const express = require('express'); const router = express.Router(); +const passport = require('passport'); const exampleController = require('../controllers/example'); +const userController = require('../controllers/user'); router.get('/', exampleController.index); +router.get('/protected', passport.authenticate('jwt', {session: false}), exampleController.index); +router.post('/register', userController.register); +router.post('/login', userController.login); module.exports = router; -- cgit v1.2.3