koas-security
Version:
Koas security checks if a request matches the security requirement of an operation. For example, given the following partial OpenAPI document:
75 lines (74 loc) • 3.24 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.security = void 0;
const apiKey_1 = require("./apiKey");
const http_1 = require("./http");
const oauth2_1 = require("./oauth2");
/**
* Authenticate users based on OpenAPI security schemes and security requirements.
*
* @param options - A mapping of OpenAPI security definition keys to user getter functions.
* @returns A Koas plugn for authenticating users.
*/
function security(options) {
return ({ document, resolveRef }) => {
const securityChecks = {};
// Work around the fact that the unaugmented options have no keys.
const opts = options;
for (const [key, schemeOrRef] of Object.entries(document.components.securitySchemes || [])) {
if (!opts[key]) {
throw new Error(`No user getter was defined for security scheme: ${key}`);
}
const scheme = resolveRef(schemeOrRef);
switch (scheme.type) {
case 'apiKey':
securityChecks[key] = (0, apiKey_1.apiKeySecurityCheck)(scheme, opts[key]);
break;
case 'http':
securityChecks[key] = (0, http_1.httpSecurityCheck)(scheme, opts[key]);
break;
case 'oauth2':
case 'openIdConnect':
securityChecks[key] = (0, oauth2_1.oauth2SecurityCheck)(scheme, opts[key]);
break;
default:
throw new Error(`Unknown security scheme: ${JSON.stringify(scheme)}`);
}
}
return async (ctx, next) => {
const { operationObject } = ctx.openApi;
if (!operationObject || !operationObject.security) {
return next();
}
for (const securityRequirementObject of operationObject.security) {
const users = {};
const clients = {};
try {
await Promise.all(Object.entries(securityRequirementObject).map(async ([key, requiredScopes]) => {
const pair = await securityChecks[key](ctx, requiredScopes);
if (!pair || !pair[0]) {
throw new Error(`Unauthorized using security requirement: ${key}`);
}
[users[key]] = pair;
if (pair[1]) {
[, clients[key]] = pair;
}
}));
}
catch {
continue;
}
ctx.users = users;
ctx.clients = clients;
// @ts-expect-error The type of ctx.user is never, because it’s not augmented yet.
[ctx.user] = Object.values(users);
// @ts-expect-error The type of ctx.client is never, because it’s not augmented yet.
[ctx.client] = Object.values(clients);
ctx.openApi.securityRequirementObject = securityRequirementObject;
return next();
}
return ctx.throw(401);
};
};
}
exports.security = security;