Implement auth with jwt and add endpoints
This commit is contained in:
parent
fce5a162d3
commit
4b5a5b2477
@ -6,6 +6,7 @@ module.exports = {
|
|||||||
updateAccount,
|
updateAccount,
|
||||||
deleteAccount,
|
deleteAccount,
|
||||||
getMeetingsByAccountId,
|
getMeetingsByAccountId,
|
||||||
|
getAccountByEmail,
|
||||||
};
|
};
|
||||||
|
|
||||||
function addAccount(data) {
|
function addAccount(data) {
|
||||||
@ -67,3 +68,18 @@ function getAccountById(id) {
|
|||||||
'latest_time',
|
'latest_time',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getAccountByEmail(email) {
|
||||||
|
return db('account')
|
||||||
|
.where({ email })
|
||||||
|
.first()
|
||||||
|
.select(
|
||||||
|
'id',
|
||||||
|
'username',
|
||||||
|
'password',
|
||||||
|
'email',
|
||||||
|
'timezone',
|
||||||
|
'earliest_time',
|
||||||
|
'latest_time',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -3,10 +3,11 @@ const router = express.Router();
|
|||||||
const bcrypt = require('bcryptjs');
|
const bcrypt = require('bcryptjs');
|
||||||
|
|
||||||
const Account = require('../models/accountModel');
|
const Account = require('../models/accountModel');
|
||||||
|
const { saltingRounds } = require('../../config/config');
|
||||||
|
|
||||||
router.post('/', async (req, res) => {
|
router.post('/', async (req, res) => {
|
||||||
const data = { ...req.body };
|
const data = { ...req.body };
|
||||||
const hash = bcrypt.hashSync(data.password, 14);
|
const hash = bcrypt.hashSync(data.password, saltingRounds);
|
||||||
data.password = hash;
|
data.password = hash;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -22,7 +23,7 @@ router.put('/:id', async (req, res) => {
|
|||||||
const id = req.params.id;
|
const id = req.params.id;
|
||||||
|
|
||||||
if (data.password) {
|
if (data.password) {
|
||||||
const hash = bcrypt.hashSync(data.password, 14);
|
const hash = bcrypt.hashSync(data.password, 10);
|
||||||
data.password = hash;
|
data.password = hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,4 +79,18 @@ router.get('/:id', async (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.get('/:email', async (req, res) => {
|
||||||
|
const email = req.params.email;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const account = await Account.getAccountByEmail(email);
|
||||||
|
res.status(200).json(account);
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({
|
||||||
|
message: `Account with ${email} doesn't exist.`,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
48
api/routes/authRoute.js
Normal file
48
api/routes/authRoute.js
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
const express = require('express');
|
||||||
|
const router = express.Router();
|
||||||
|
const bcrypt = require('bcryptjs');
|
||||||
|
|
||||||
|
const Account = require('../models/accountModel');
|
||||||
|
const { saltingRounds } = require('../../config/config');
|
||||||
|
const { generateToken } = require('../../helpers/authJwt');
|
||||||
|
|
||||||
|
router.post('/register', async (req, res) => {
|
||||||
|
const data = req.body;
|
||||||
|
data.password = bcrypt.hashSync(data.password, saltingRounds);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const [user] = await Account.addAccount(data);
|
||||||
|
const token = generateToken(user);
|
||||||
|
res.status(201).json({ user, token });
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({
|
||||||
|
message: `Failed to add new account.`,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post('/login', async (req, res) => {
|
||||||
|
let { email, password } = req.body;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const user = await Account.getAccountByEmail(email);
|
||||||
|
|
||||||
|
if (bcrypt.compareSync(password, user.password)) {
|
||||||
|
const token = generateToken(user);
|
||||||
|
|
||||||
|
res.status(200).json({
|
||||||
|
message: `Welcome ${user.username}!`,
|
||||||
|
token,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
throw new Error();
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
res.status(401).json({
|
||||||
|
message: `Invalid Credentials`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = router;
|
@ -9,6 +9,7 @@ const meetingsRoute = require('./routes/meetingRoute');
|
|||||||
const participantsRoute = require('./routes/participantRoute');
|
const participantsRoute = require('./routes/participantRoute');
|
||||||
const possibleDatesRoute = require('./routes/possibleDateRoute');
|
const possibleDatesRoute = require('./routes/possibleDateRoute');
|
||||||
const availibilityRoute = require('./routes/availibilityRoute');
|
const availibilityRoute = require('./routes/availibilityRoute');
|
||||||
|
const authRoute = require('./routes/authRoute');
|
||||||
|
|
||||||
const server = express();
|
const server = express();
|
||||||
|
|
||||||
@ -28,6 +29,7 @@ server.use('/api/meetings', meetingsRoute);
|
|||||||
server.use('/api/participants', participantsRoute);
|
server.use('/api/participants', participantsRoute);
|
||||||
server.use('/api/possible-dates', possibleDatesRoute);
|
server.use('/api/possible-dates', possibleDatesRoute);
|
||||||
server.use('/api/availibility', availibilityRoute);
|
server.use('/api/availibility', availibilityRoute);
|
||||||
|
server.use('/api/auth', authRoute);
|
||||||
|
|
||||||
server.get('/', (req, res) =>
|
server.get('/', (req, res) =>
|
||||||
res
|
res
|
||||||
|
@ -2,5 +2,6 @@ module.exports = {
|
|||||||
jwt_secret: process.env.JWT_SECRET,
|
jwt_secret: process.env.JWT_SECRET,
|
||||||
port: process.env.PORT || 3001,
|
port: process.env.PORT || 3001,
|
||||||
db_url: process.env.DATABASE_URL,
|
db_url: process.env.DATABASE_URL,
|
||||||
environment: process.env.NODE_ENV,
|
environment: process.env.NODE_ENV || 'development',
|
||||||
|
saltingRounds: process.env.SALTING_ROUNDS || 10,
|
||||||
};
|
};
|
||||||
|
36
helpers/authJwt.js
Normal file
36
helpers/authJwt.js
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
const jwt = require('jsonwebtoken');
|
||||||
|
const { jwt_secret } = require('../config/config');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
authenticate,
|
||||||
|
generateToken,
|
||||||
|
};
|
||||||
|
|
||||||
|
function generateToken(user) {
|
||||||
|
const payload = {
|
||||||
|
username: user.username,
|
||||||
|
email: user.email
|
||||||
|
};
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
expiresIn: '30d',
|
||||||
|
};
|
||||||
|
|
||||||
|
return jwt.sign(payload, jwt_secret, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
function authenticate(req, res, next) {
|
||||||
|
const token = req.get('Authorization');
|
||||||
|
|
||||||
|
if (token) {
|
||||||
|
jwt.verify(token, jwt_secret, (err, decoded) => {
|
||||||
|
if (err) return res.status(401).json(err);
|
||||||
|
req.decoded = decoded;
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return res.status(401).json({
|
||||||
|
error: 'No token provided, must be set on the Authorization Header',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
96
package-lock.json
generated
96
package-lock.json
generated
@ -172,6 +172,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"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": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk="
|
||||||
|
},
|
||||||
"buffer-writer": {
|
"buffer-writer": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz",
|
||||||
@ -400,6 +405,14 @@
|
|||||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz",
|
||||||
"integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw=="
|
"integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw=="
|
||||||
},
|
},
|
||||||
|
"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==",
|
||||||
|
"requires": {
|
||||||
|
"safe-buffer": "^5.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"ee-first": {
|
"ee-first": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||||
@ -1090,6 +1103,54 @@
|
|||||||
"resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz",
|
||||||
"integrity": "sha1-4mJbrbwNZ8dTPp7cEGjFh65BN+8="
|
"integrity": "sha1-4mJbrbwNZ8dTPp7cEGjFh65BN+8="
|
||||||
},
|
},
|
||||||
|
"jsonwebtoken": {
|
||||||
|
"version": "8.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz",
|
||||||
|
"integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==",
|
||||||
|
"requires": {
|
||||||
|
"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": "^5.6.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"ms": {
|
||||||
|
"version": "2.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||||
|
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||||
|
},
|
||||||
|
"semver": {
|
||||||
|
"version": "5.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
||||||
|
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"jwa": {
|
||||||
|
"version": "1.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
|
||||||
|
"integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
|
||||||
|
"requires": {
|
||||||
|
"buffer-equal-constant-time": "1.0.1",
|
||||||
|
"ecdsa-sig-formatter": "1.0.11",
|
||||||
|
"safe-buffer": "^5.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"jws": {
|
||||||
|
"version": "3.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
|
||||||
|
"integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
|
||||||
|
"requires": {
|
||||||
|
"jwa": "^1.4.1",
|
||||||
|
"safe-buffer": "^5.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"kind-of": {
|
"kind-of": {
|
||||||
"version": "6.0.3",
|
"version": "6.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
|
||||||
@ -1192,6 +1253,41 @@
|
|||||||
"resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz",
|
||||||
"integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc="
|
"integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc="
|
||||||
},
|
},
|
||||||
|
"lodash.includes": {
|
||||||
|
"version": "4.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
|
||||||
|
"integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8="
|
||||||
|
},
|
||||||
|
"lodash.isboolean": {
|
||||||
|
"version": "3.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
|
||||||
|
"integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY="
|
||||||
|
},
|
||||||
|
"lodash.isinteger": {
|
||||||
|
"version": "4.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
|
||||||
|
"integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M="
|
||||||
|
},
|
||||||
|
"lodash.isnumber": {
|
||||||
|
"version": "3.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
|
||||||
|
"integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w="
|
||||||
|
},
|
||||||
|
"lodash.isplainobject": {
|
||||||
|
"version": "4.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
|
||||||
|
"integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs="
|
||||||
|
},
|
||||||
|
"lodash.isstring": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
|
||||||
|
"integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE="
|
||||||
|
},
|
||||||
|
"lodash.once": {
|
||||||
|
"version": "4.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
|
||||||
|
"integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w="
|
||||||
|
},
|
||||||
"make-iterator": {
|
"make-iterator": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz",
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
"dotenv": "^8.2.0",
|
"dotenv": "^8.2.0",
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
"helmet": "^3.22.0",
|
"helmet": "^3.22.0",
|
||||||
|
"jsonwebtoken": "^8.5.1",
|
||||||
"knex": "^0.21.1",
|
"knex": "^0.21.1",
|
||||||
"pg": "^8.0.3",
|
"pg": "^8.0.3",
|
||||||
"pgtools": "^0.3.0",
|
"pgtools": "^0.3.0",
|
||||||
|
Loading…
Reference in New Issue
Block a user