diff options
author | 2020-11-22 13:49:09 +0100 | |
---|---|---|
committer | 2020-11-22 13:49:09 +0100 | |
commit | 4569b85489e863465395f84e995dd3fdc44471b4 (patch) | |
tree | 6e4d27883809c94c8b3f3b87159d85c7f3874bbd /server | |
parent | 81ddf9b700bc48a1f8e472209f080f9c1d9a9b09 (diff) | |
download | website_creator-4569b85489e863465395f84e995dd3fdc44471b4.tar.gz website_creator-4569b85489e863465395f84e995dd3fdc44471b4.tar.bz2 website_creator-4569b85489e863465395f84e995dd3fdc44471b4.zip |
implement refresh tokens
Diffstat (limited to 'server')
-rw-r--r-- | server/middleware/auth.js | 30 | ||||
-rw-r--r-- | server/models/User.js | 31 | ||||
-rw-r--r-- | server/routes/user.js | 25 |
3 files changed, 61 insertions, 25 deletions
diff --git a/server/middleware/auth.js b/server/middleware/auth.js index 42d93a4..462b100 100644 --- a/server/middleware/auth.js +++ b/server/middleware/auth.js @@ -9,16 +9,32 @@ const auth = async (req, res, next) => { throw new Error(); } - const decoded = jwt.verify(token, 'replaceThisWithSecretString'); - const user = await User.findOne({ _id: decoded._id, 'tokens.token': token }); + try { + const decoded = jwt.verify(token, 'replaceThisWithSecretString'); + req.userId = decoded._id; + req.refreshToken = decoded.ref; + return next(); + } catch(er) { + if (er.message && er.message === 'jwt expired') { + const { _id, ref } = jwt.decode(token, 'replaceThisWithSecretString'); + const user = await User.findById(_id); + + if (!user) { + throw new Error(); + } + + if (user.sessions.filter(s => s.ref === ref).length > 0) { + req.userId = _id; + req.refreshToken = ref; + req.newToken = await user.generateJwtToken(res.req.refreshToken);; + return next(); + } + + throw new Error(); + } - if (!user) { throw new Error(); } - - req.token = token; - req.user = user; - next(); } catch (err) { res.redirect('/login'); } diff --git a/server/models/User.js b/server/models/User.js index 4fa6ffe..e777878 100644 --- a/server/models/User.js +++ b/server/models/User.js @@ -1,5 +1,6 @@ const mongoose = require("mongoose"); const bcrypt = require('bcryptjs'); +const randtoken = require('rand-token'); const jwt = require('jsonwebtoken'); const userSchema = new mongoose.Schema({ @@ -23,22 +24,36 @@ const userSchema = new mongoose.Schema({ min: 4, max: 1024, }, - tokens: [{ - token: { + sessions: [{ + ref: { type: String, required: true } }] }); -userSchema.methods.generateAuthToken = async function () { - const user = this; - const token = jwt.sign({ _id: user._id.toString() }, 'replaceThisWithSecretString') +userSchema.methods.generateJwtToken = async function (currentRef) { + const ref = currentRef ? currentRef : randtoken.uid(256); + + if (!currentRef) { + this.sessions = this.sessions.concat({ ref }); + this.save(); + } + + return jwt.sign( + { _id: this._id.toString(), ref }, + 'replaceThisWithSecretString', + { expiresIn: 300 } + ); +} - user.tokens = user.tokens.concat({ token }); - user.save(); +userSchema.methods.endSession = async function (ref) { + this.sessions = this.sessions.filter((session) => { + return session.ref !== ref; + }); - return token; + await this.save(); + return null; } userSchema.statics.findByCredentials = async (email, password) => { diff --git a/server/routes/user.js b/server/routes/user.js index d1100bc..b3bdee3 100644 --- a/server/routes/user.js +++ b/server/routes/user.js @@ -1,14 +1,19 @@ const router = require('express').Router(); const User = require('../models/User'); const auth = require('../middleware/auth'); +const jwt = require('jsonwebtoken'); + +router.get('/me', auth, async (req, res) => { + const user = await User.findById(req.userId); + res.json({ email: user.email }); +}) router.post('/register', async (req, res) => { const user = new User(req.body); try { await user.save(); - const token = await user.generateAuthToken(); - res.status(201).send({ user, token }); + res.status(201).send({ email: user.email }); } catch(err) { if (err._message) { res.status(422).send(err._message); @@ -23,10 +28,10 @@ router.post('/register', async (req, res) => { router.post('/login', async (req, res) => { try { const user = await User.findByCredentials(req.body.email, req.body.password); - const token = await user.generateAuthToken(); + const token = await user.generateJwtToken(); res .cookie('token', token, { - expires: new Date(Date.now() + 604800000), + maxAge: 604800000, secure: false, httpOnly: true, }) @@ -39,12 +44,12 @@ router.post('/login', async (req, res) => { router.post('/logout', auth, async (req, res) => { try { - req.user.tokens = req.user.tokens.filter((token) => { - return token.token !== req.token; - }); - await req.user.save(); - - res.status(204).send(); + const user = await User.findById(req.userId); + await user.endSession(req.refreshToken); + res + .clearCookie('token') + .status(204) + .send(); } catch (err) { res.status(500).send(); } |