diff --git a/packages/oas/src/operation/index.ts b/packages/oas/src/operation/index.ts index ffd5af22..0a7af7b3 100644 --- a/packages/oas/src/operation/index.ts +++ b/packages/oas/src/operation/index.ts @@ -3,6 +3,7 @@ import type { getParametersAsJSONSchemaOptions } from './lib/get-parameters-as-j import type { RequestBodyExamples } from './lib/get-requestbody-examples.js'; import type { ResponseExamples } from './lib/get-response-examples.js'; import type { Extensions } from '../extensions.js'; +import type { SecurityType } from '../types.js'; import type { OpenAPIV3, OpenAPIV3_1 } from 'openapi-types'; import findSchemaDefinition from '../lib/find-schema-definition.js'; @@ -18,8 +19,6 @@ import { getRequestBodyExamples } from './lib/get-requestbody-examples.js'; import { getResponseAsJSONSchema } from './lib/get-response-as-json-schema.js'; import { getResponseExamples } from './lib/get-response-examples.js'; -type SecurityType = 'apiKey' | 'Basic' | 'Bearer' | 'Cookie' | 'Header' | 'http' | 'OAuth2' | 'Query'; - export class Operation { /** * Schema of the operation from the API Definition. @@ -224,6 +223,7 @@ export class Operation { security: { ...security, _key: key, + _requirements: requirement[key], }, }; }); @@ -252,8 +252,12 @@ export class Operation { if (!prev[security.type]) prev[security.type] = []; // Only add schemes we haven't seen yet. - const exists = prev[security.type].findIndex(sec => sec._key === security.security._key); - if (exists < 0) { + const exists = prev[security.type].some(sec => sec._key === security.security._key); + if (!exists) { + // Since an operation can require the same security scheme several times (each with different scope requirements), + // including the `_requirements` in this object would be misleading since we dedupe the security schemes. + // eslint-disable-next-line no-underscore-dangle + if (security.security?._requirements) delete security.security._requirements; prev[security.type].push(security.security); } }); diff --git a/packages/oas/src/types.ts b/packages/oas/src/types.ts index 8975f795..85520113 100644 --- a/packages/oas/src/types.ts +++ b/packages/oas/src/types.ts @@ -47,6 +47,11 @@ export interface User { }[]; } +/** + * The type of security scheme. Used by `operation.getSecurityWithTypes()` and `operation.prepareSecurity()`. + */ +export type SecurityType = 'apiKey' | 'Basic' | 'Bearer' | 'Cookie' | 'Header' | 'http' | 'OAuth2' | 'Query'; + export type HttpMethods = | OpenAPIV3_1.HttpMethods | OpenAPIV3.HttpMethods @@ -232,8 +237,17 @@ export type SecuritySchemeObject = OpenAPIV3_1.SecuritySchemeObject | OpenAPIV3. export type SecuritySchemesObject = Record; export type KeyedSecuritySchemeObject = SecuritySchemeObject & { + /** + * The key for the given security scheme object + */ _key: string; + /** + * An array of required scopes for the given security scheme object. + * Used for `oauth2` security scheme types. + */ + _requirements?: string[]; + // `x-default` is our custom extension for specifying auth defaults. // https://docs.readme.com/docs/openapi-extensions#authentication-defaults 'x-default'?: number | string; diff --git a/packages/oas/test/operation/index.test.ts b/packages/oas/test/operation/index.test.ts index 71fe51d1..44eefef9 100644 --- a/packages/oas/test/operation/index.test.ts +++ b/packages/oas/test/operation/index.test.ts @@ -496,6 +496,7 @@ describe('#getSecurityWithTypes()', () => { { security: { _key: 'auth', + _requirements: [], scheme: 'basic', type: 'http', }, @@ -510,6 +511,7 @@ describe('#getSecurityWithTypes()', () => { { security: { _key: 'auth', + _requirements: [], scheme: 'basic', type: 'http', }, @@ -672,7 +674,7 @@ describe('#getSecurityWithTypes()', () => { [ { type: 'Query', - security: { type: 'apiKey', name: 'api_key', in: 'query', _key: 'api_key' }, + security: { type: 'apiKey', name: 'api_key', in: 'query', _key: 'api_key', _requirements: [] }, }, ], ]);