diff --git a/.changeset/stupid-hats-reflect.md b/.changeset/stupid-hats-reflect.md
new file mode 100644
index 0000000000..3c370a07bf
--- /dev/null
+++ b/.changeset/stupid-hats-reflect.md
@@ -0,0 +1,5 @@
+---
+'@gitbook/react-openapi': patch
+---
+
+Handle optional security headers
diff --git a/packages/react-openapi/src/OpenAPISecurities.tsx b/packages/react-openapi/src/OpenAPISecurities.tsx
index 465afeb088..fcdd003fd6 100644
--- a/packages/react-openapi/src/OpenAPISecurities.tsx
+++ b/packages/react-openapi/src/OpenAPISecurities.tsx
@@ -1,8 +1,11 @@
-import type { OpenAPIV3_1 } from '@gitbook/openapi-parser';
import { InteractiveSection } from './InteractiveSection';
import { Markdown } from './Markdown';
import { OpenAPISchemaName } from './OpenAPISchemaName';
-import type { OpenAPIClientContext, OpenAPIOperationData } from './types';
+import type {
+ OpenAPIClientContext,
+ OpenAPIOperationData,
+ OpenAPISecurityWithRequired,
+} from './types';
import { resolveDescription } from './utils';
/**
@@ -50,26 +53,36 @@ export function OpenAPISecurities(props: {
);
}
-function getLabelForType(security: OpenAPIV3_1.SecuritySchemeObject) {
+function getLabelForType(security: OpenAPISecurityWithRequired) {
switch (security.type) {
case 'apiKey':
return (
);
case 'http':
if (security.scheme === 'basic') {
- return ;
+ return (
+
+ );
}
if (security.scheme === 'bearer') {
const description = resolveDescription(security);
return (
<>
-
+
{/** Show a default description if none is provided */}
{!description ? (
;
+ return ;
case 'oauth2':
- return ;
+ return ;
case 'openIdConnect':
- return ;
+ return ;
default:
// @ts-ignore
return security.type;
diff --git a/packages/react-openapi/src/resolveOpenAPIOperation.ts b/packages/react-openapi/src/resolveOpenAPIOperation.ts
index 295f2b79ce..ba65b8bd66 100644
--- a/packages/react-openapi/src/resolveOpenAPIOperation.ts
+++ b/packages/react-openapi/src/resolveOpenAPIOperation.ts
@@ -40,16 +40,27 @@ export async function resolveOpenAPIOperation(
}
const servers = 'servers' in schema ? (schema.servers ?? []) : [];
- const security = flattenSecurities(operation.security ?? schema.security ?? []);
+ const security: OpenAPIV3_1.SecurityRequirementObject[] =
+ operation.security ?? schema.security ?? [];
+
+ // If security includes an empty object, it means that the security is optional
+ const isOptionalSecurity = security.some((entry) => Object.keys(entry).length === 0);
+ const flatSecurities = flattenSecurities(security);
// Resolve securities
const securities: OpenAPIOperationData['securities'] = [];
- for (const entry of security) {
+ for (const entry of flatSecurities) {
const securityKey = Object.keys(entry)[0];
if (securityKey) {
const securityScheme = schema.components?.securitySchemes?.[securityKey];
if (securityScheme && !checkIsReference(securityScheme)) {
- securities.push([securityKey, securityScheme]);
+ securities.push([
+ securityKey,
+ {
+ ...securityScheme,
+ required: !isOptionalSecurity,
+ },
+ ]);
}
}
}
diff --git a/packages/react-openapi/src/types.ts b/packages/react-openapi/src/types.ts
index 39b9899e9b..94dad6f5d7 100644
--- a/packages/react-openapi/src/types.ts
+++ b/packages/react-openapi/src/types.ts
@@ -57,6 +57,8 @@ export interface OpenAPIContext extends OpenAPIClientContext {
specUrl: string;
}
+export type OpenAPISecurityWithRequired = OpenAPIV3.SecuritySchemeObject & { required?: boolean };
+
export interface OpenAPIOperationData extends OpenAPICustomSpecProperties {
path: string;
method: string;
@@ -68,5 +70,5 @@ export interface OpenAPIOperationData extends OpenAPICustomSpecProperties {
operation: OpenAPIV3.OperationObject;
/** Securities that should be used for this operation */
- securities: [string, OpenAPIV3.SecuritySchemeObject][];
+ securities: [string, OpenAPISecurityWithRequired][];
}