Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [2.4.1-beta-1] - 2026-06-26

### Fixed
- Fix crash when `securitySchemes` contains `type: apiKey` or other non-OAuth2 schemes.
- Fix schema validation crash on 204 No Content endpoints when `validate_schema: true`.
- Resolve external `$ref` (HTTP/HTTPS URLs) instead of crashing with `TypeError`. External schemas are fetched, cached, and inlined at parse time using Node's built-in `http`/`https` modules.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,18 @@ module.exports = function() {

return function get(oAuthDefinition){
let definition
let definitionKey
for (const i in oAuthDefinition) {
definition = oAuthDefinition[i];
if (oAuthDefinition[i]?.type === 'oauth2') {
definition = oAuthDefinition[i]
definitionKey = i
break
}
}
const data = parseUrl(definition.flows)
if (!data) return null
const authKey = _.keys(globalThis.definition.security[0])[0]
return generateDefinition(data,authKey)
if (!definition) return null
const data = parseUrl(definition.flows)
if (!data) return null
return generateDefinition(data, definitionKey)
}

function generateDefinition(data,auth){
Expand Down Expand Up @@ -90,6 +95,7 @@ module.exports = function() {
}

function parseUrl(flows) {
if (!flows) return null
let targetFlow = null
for (const flowName of FLOW_PRIORITY) {
if (flows[flowName]?.tokenUrl) {
Expand Down
84 changes: 84 additions & 0 deletions test/parser-authorization-definition.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/** Part of APIAddicts. See LICENSE file or full copyright and licensing details. Supported by Madrid Digital and CloudAPPi **/

const assert = require('node:assert');
const get = require('../src/parser/openapi3/authorizationDefinition.js');

describe('parser-authorization-definition', () => {

it('null apiKey only oa3', () => {
globalThis.definition = { security: [{ ApiKeyAuth: [] }] };
const result = get({ ApiKeyAuth: { type: 'apiKey', in: 'header', name: 'X-API-Key' } });
assert.strictEqual(result, null);
});

it('null http only oa3', () => {
globalThis.definition = { security: [{ BasicAuth: [] }] };
const result = get({ BasicAuth: { type: 'http', scheme: 'basic' } });
assert.strictEqual(result, null);
});

it('null empty schemes oa3', () => {
globalThis.definition = { security: [] };
const result = get({});
assert.strictEqual(result, null);
});

it('oauth2 definition apiKey first oa3', () => {
globalThis.definition = { security: [{ OAuth2: ['read'] }] };
const result = get({
ApiKeyAuth: { type: 'apiKey', in: 'header', name: 'X-API-Key' },
OAuth2: {
type: 'oauth2',
flows: {
clientCredentials: { tokenUrl: 'https://auth.example.com/token', scopes: {} }
}
}
});
assert.ok(result !== null);
assert.ok(result.item[0].name.includes('OAuth2'));
});

it('oauth2 definition oauth2 first oa3', () => {
globalThis.definition = { security: [{ OAuth2: ['read'] }] };
const result = get({
OAuth2: {
type: 'oauth2',
flows: {
clientCredentials: { tokenUrl: 'https://auth.example.com/token', scopes: {} }
}
},
ApiKeyAuth: { type: 'apiKey', in: 'header', name: 'X-API-Key' }
});
assert.ok(result !== null);
assert.ok(result.item[0].name.includes('OAuth2'));
});

it('oauth2 definition no global security oa3', () => {
globalThis.definition = { security: undefined };
const result = get({
OAuth2: {
type: 'oauth2',
flows: {
password: { tokenUrl: 'https://auth.example.com/token', scopes: {} }
}
}
});
assert.ok(result !== null);
assert.ok(result.item[0].name.includes('OAuth2'));
});

it('oauth2 definition only oauth2 oa3', () => {
globalThis.definition = { security: [{ MyOAuth: [] }] };
const result = get({
MyOAuth: {
type: 'oauth2',
flows: {
password: { tokenUrl: 'https://auth.example.com/token', scopes: {} }
}
}
});
assert.ok(result !== null);
assert.ok(result.item[0].name.includes('MyOAuth'));
});

});