express-swagger-oauth-scopes
Express.js middleware to grant/block access to endpoints based on Swagger security entries

Note that it should be applied within router and not globally on application since it depends on route being already resolved for the request.
Alternatively you can explicitly pass path to a endpoint when instantiating a middleware (this is necessary when you are using middleware inside Google Cloud Function which does not provide access to router).
const swaggerOauth = require('express-swagger-oauth-scopes').middleware;
const swaggerService = require('../services/swagger.service');
const authUtils = require('../utils/auth.utils');
const swaggerDocument = swaggerService.getSwaggerSync()
function getNewSwaggerOauthInstance() {
return swaggerOauth(swaggerDocument, authUtils.getPermissionsFromRequest);
}
function getNewSwaggerOauthInstanceExplicitPath(path) {
return swaggerOauth(swaggerDocument, authUtils.getPermissionsFromRequest, 'oauth', path);
}
router.post('/users',
getNewSwaggerOauthInstance(),
async (req, res, next) => {
try {
} catch (e) {
return next(e);
}
});
router.post('/users-explicit',
getNewSwaggerOauthInstanceExplicitPath('/users-explicit'),
async (req, res, next) => {
try {
} catch (e) {
return next(e);
}
});
Recommended way to use this library is together with swagger-jsdoc (https://github.com/Surnet/swagger-jsdoc) and
swagger-combine (https://github.com/maxdome/swagger-combine) so that you could keep security definition together
with controller implementation:
const swaggerOauth = require('express-swagger-oauth-scopes').middleware;
const swaggerService = require('../services/swagger.service');
const authUtils = require('../utils/auth.utils');
const swaggerDocument = swaggerService.getSwaggerSync()
function getNewSwaggerOauthInstance() {
return swaggerOauth(swaggerDocument, authUtils.getPermissionsFromRequest);
}
router.post('/users',
getNewSwaggerOauthInstance(),
async (req, res, next) => {
try {
} catch (e) {
return next(e);
}
});
Reference implementation of a swagger.service:
const swaggerJSDoc = require('swagger-jsdoc');
const objectionSwagger = require('objection-swagger');
const swaggerCombine = require('swagger-combine');
const mkdirp = require('mkdirp-promise');
const config = require('config');
const yaml = require('js-yaml');
const fs = require('fs');
const path = require('path');
const _ = require('lodash');
const PATH_TO_COMBINED_SWAGGER = config.swagger.pathToCombinedSwagger;
const PATH_TO_MODELS = config.models.path;
let builtSwaggerSchema;
const options = {
swaggerDefinition: {
info: {
title: 'User Management System',
version: '1.0.0'
},
},
apis: [
'./controllers/**/*.js',
'./modules/**/controllers/**/*.js'
],
};
const modelContainer = require('require-all')({
dirname: PATH_TO_MODELS,
filter: /(.+model)\.js$/,
recursive: false
});
const models = _.values(modelContainer);
async function generateSwagger() {
const swaggerDir = path.dirname(PATH_TO_COMBINED_SWAGGER);
const pathToTmpSwagger = `${swaggerDir}/tmpSwagger.yaml`;
const swaggerFromControllers = swaggerJSDoc(options);
const swaggerYaml = yaml.safeDump(swaggerFromControllers);
await mkdirp(swaggerDir);
fs.writeFileSync(pathToTmpSwagger, swaggerYaml);
await objectionSwagger.saveSchema(models, swaggerDir);
combinedSwaggerSchema = await swaggerCombine(pathToTmpSwagger);
fs.writeFileSync(PATH_TO_COMBINED_SWAGGER, yaml.safeDump(combinedSwaggerSchema));
return combinedSwaggerSchema;
}
async function getSwagger() {
if (builtSwaggerSchema) {
return builtSwaggerSchema;
}
return generateSwagger();
}
function getSwaggerSync() {
if (builtSwaggerSchema) {
return builtSwaggerSchema;
}
throw new Error('Swagger document was not yet built, please ensure that you are calling this method after initialization phase is completed.');
}
module.exports = {
generateSwagger,
getSwagger,
getSwaggerSync
};