removes duplicative JWT strategies, flattens cookie jwt retrieval into JWT strategy itself, removes sessions

This commit is contained in:
James
2020-07-06 09:35:23 -04:00
parent a4ef486e1a
commit df4b5cced7
12 changed files with 60 additions and 51 deletions

19
src/auth/getExtractJWT.js Normal file
View File

@@ -0,0 +1,19 @@
const getExtractJWT = config => (req) => {
const jwtFromHeader = req.get('Authorization');
if (jwtFromHeader && jwtFromHeader.indexOf('JWT ') === 0) {
return jwtFromHeader.replace('JWT ', '');
}
if (req.cookies) {
const jwt = req.cookies[`${config.cookiePrefix}-token`];
if (jwt) {
return jwt;
}
}
return null;
};
module.exports = getExtractJWT;

View File

@@ -1,11 +1,15 @@
/* eslint-disable no-param-reassign */
const { refresh } = require('../../operations');
const getExtractJWT = require('../../getExtractJWT');
const refreshResolver = (config, collection) => async (_, __, context) => {
const extractJWT = getExtractJWT(config);
const token = extractJWT(context);
const options = {
config,
collection,
authorization: context.headers.authorization,
token,
req: context,
};

10
src/auth/init.js Normal file
View File

@@ -0,0 +1,10 @@
const passport = require('passport');
const AnonymousStrategy = require('passport-anonymous');
const jwtStrategy = require('./strategies/jwt');
function initAuth() {
passport.use(new AnonymousStrategy.Strategy());
passport.use('jwt', jwtStrategy(this.config, this.collections));
}
module.exports = initAuth;

View File

@@ -25,10 +25,9 @@ const refresh = async (args) => {
const opts = {};
opts.expiresIn = options.collection.config.auth.tokenExpiration;
if (typeof options.authorization !== 'string') throw new Forbidden();
if (typeof options.token !== 'string') throw new Forbidden();
const token = options.authorization.replace('JWT ', '');
const payload = jwt.verify(token, secret, {});
const payload = jwt.verify(options.token, secret, {});
delete payload.iat;
delete payload.exp;
const refreshedToken = jwt.sign(payload, secret, opts);

View File

@@ -1,15 +1,19 @@
const httpStatus = require('http-status');
const formatErrorResponse = require('../../express/responses/formatError');
const { refresh } = require('../operations');
const getExtractJWT = require('../getExtractJWT');
const refreshHandler = config => async (req, res) => {
try {
const extractJWT = getExtractJWT(config);
const token = extractJWT(req);
const result = await refresh({
req,
res,
collection: req.collection,
config,
authorization: req.headers.authorization,
token,
});
return res.status(200).json({

View File

@@ -1,11 +1,16 @@
const passportJwt = require('passport-jwt');
const getExtractJWT = require('../getExtractJWT');
const JwtStrategy = passportJwt.Strategy;
const { ExtractJwt } = passportJwt;
module.exports = (config, collections) => {
const opts = {};
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderWithScheme('JWT');
const opts = {
session: false,
};
const extractJWT = getExtractJWT(config);
opts.jwtFromRequest = extractJWT;
opts.secretOrKey = config.secret;
return new JwtStrategy(opts, async (token, done) => {
@@ -17,9 +22,9 @@ module.exports = (config, collections) => {
const json = user.toJSON({ virtuals: true });
json.collection = collection.config.slug;
return done(null, json);
done(null, json);
} catch (err) {
return done(null, false);
done(null, false);
}
});
};

View File

@@ -8,7 +8,6 @@ const mongooseHidden = require('mongoose-hidden')({
const passport = require('passport');
const passportLocalMongoose = require('passport-local-mongoose');
const LocalStrategy = require('passport-local').Strategy;
const jwtStrategy = require('../auth/strategies/jwt');
const apiKeyStrategy = require('../auth/strategies/apiKey');
const collectionRoutes = require('./routes');
const buildSchema = require('./buildSchema');
@@ -137,10 +136,6 @@ function registerCollections() {
passport.use(`${AuthCollection.config.slug}-api-key`, apiKeyStrategy(AuthCollection));
}
passport.use(`${AuthCollection.config.slug}-jwt`, jwtStrategy(this.config, this.collections));
passport.serializeUser(AuthCollection.Model.serializeUser());
passport.deserializeUser(AuthCollection.Model.deserializeUser());
this.router.use(authRoutes(AuthCollection, this.config, this.sendEmail));
} else {
this.router.use(collectionRoutes(this.collections[formattedCollection.slug]));

View File

@@ -2,21 +2,14 @@ const passport = require('passport');
module.exports = (config) => {
const methods = config.collections.reduce((enabledMethods, collection) => {
if (collection.auth) {
const collectionMethods = [
`${collection.slug}-jwt`,
...enabledMethods,
];
if (collection.auth.enableAPIKey) {
collectionMethods.unshift(`${collection.slug}-api-key`);
}
if (collection.auth && collection.auth.useAPIKey) {
const collectionMethods = [...enabledMethods];
collectionMethods.unshift(`${collection.slug}-api-key`);
return collectionMethods;
}
return enabledMethods;
}, ['anonymous']);
}, ['jwt', 'anonymous']);
return passport.authenticate(methods, { session: false });
};

View File

@@ -1,15 +0,0 @@
const createAuthHeaderFromCookie = config => (req, _, next) => {
const existingAuthHeader = req.get('Authorization');
if (req.cookies) {
const token = req.cookies[`${config.cookiePrefix}-token`];
if (!existingAuthHeader && token) {
req.headers.authorization = `JWT ${token}`;
}
}
next();
};
module.exports = createAuthHeaderFromCookie;

View File

@@ -1,6 +1,5 @@
const express = require('express');
const passport = require('passport');
const AnonymousStrategy = require('passport-anonymous');
const compression = require('compression');
const bodyParser = require('body-parser');
const methodOverride = require('method-override');
@@ -8,18 +7,13 @@ const cookieParser = require('cookie-parser');
const qsMiddleware = require('qs-middleware');
const fileUpload = require('express-fileupload');
const localizationMiddleware = require('../../localization/middleware');
const createAuthHeaderFromCookie = require('./createAuthHeaderFromCookie');
const authenticate = require('./authenticate');
const identifyAPI = require('./identifyAPI');
const middleware = (config) => {
passport.use(new AnonymousStrategy.Strategy());
return [
cookieParser(),
createAuthHeaderFromCookie(config),
passport.initialize(),
passport.session(),
authenticate(config),
express.json(),
methodOverride('X-HTTP-Method-Override'),

View File

@@ -3,7 +3,6 @@ const passport = require('passport');
const cookieParser = require('cookie-parser');
const getExecuteStaticPolicy = require('../auth/getExecuteStaticPolicy');
const authenticate = require('./middleware/authenticate');
const createAuthHeaderFromCookie = require('./middleware/createAuthHeaderFromCookie');
function initStatic() {
Object.entries(this.collections).forEach(([_, collection]) => {
@@ -13,9 +12,7 @@ function initStatic() {
const router = express.Router();
router.use(cookieParser());
router.use(createAuthHeaderFromCookie(this.config));
router.use(passport.initialize());
router.use(passport.session());
router.use(authenticate(this.config));
router.use(getExecuteStaticPolicy(collection));

View File

@@ -8,6 +8,7 @@ const authenticate = require('./express/middleware/authenticate');
const connectMongoose = require('./mongoose/connect');
const expressMiddleware = require('./express/middleware');
const initAdmin = require('./express/admin');
const initAuth = require('./auth/init');
const initCollections = require('./collections/init');
const initGlobals = require('./globals/init');
const initStatic = require('./express/static');
@@ -30,6 +31,7 @@ class Payload {
this.router = express.Router();
this.collections = {};
this.initAuth = initAuth.bind(this);
this.initCollections = initCollections.bind(this);
this.initGlobals = initGlobals.bind(this);
this.buildEmail = buildEmail.bind(this);
@@ -43,8 +45,10 @@ class Payload {
// Setup & initialization
connectMongoose(this.config.mongoURL);
this.router.use(...expressMiddleware(this.config));
this.router.use(...expressMiddleware(this.config, this.collections));
this.initAuth();
this.initCollections();
this.initGlobals();
this.initAdmin();