diff --git a/demo/examples/petstore.yaml b/demo/examples/petstore.yaml index 7b16f7231..ae80369bb 100644 --- a/demo/examples/petstore.yaml +++ b/demo/examples/petstore.yaml @@ -37,6 +37,7 @@ info: Petstore offers two forms of authentication: - API Key - OAuth2 + OAuth2 - an open protocol to allow secure authorization in a simple and standard method from web, mobile and desktop applications. @@ -120,6 +121,13 @@ paths: - petstore_auth: - "write:pets" - "read:pets" + - api_key: [] + - ApiKeyAuth: [] + - BasicAuth: [] + - BearerAuth: [] + - OAuth2: [] + - OpenID: [] + x-codeSamples: - lang: "C#" source: | @@ -1223,13 +1231,29 @@ components: type: apiKey name: api_key in: header - examples: - Order: - value: - quantity: 1 - shipDate: "2018-10-19T16:46:45Z" - status: placed - complete: false + BasicAuth: + type: http + scheme: basic + BearerAuth: + type: http + scheme: bearer + ApiKeyAuth: + type: apiKey + in: header + name: X-API-Key + OpenID: + type: openIdConnect + openIdConnectUrl: https://example.com/.well-known/openid-configuration + OAuth2: + type: oauth2 + flows: + authorizationCode: + authorizationUrl: https://example.com/oauth/authorize + tokenUrl: https://example.com/oauth/token + scopes: + read: Grants read access + write: Grants write access + admin: Grants access to admin operations x-webhooks: newPet: post: diff --git a/packages/docusaurus-plugin-openapi-docs/src/markdown/createAuthentication.ts b/packages/docusaurus-plugin-openapi-docs/src/markdown/createAuthentication.ts index 9dc47833f..013764016 100644 --- a/packages/docusaurus-plugin-openapi-docs/src/markdown/createAuthentication.ts +++ b/packages/docusaurus-plugin-openapi-docs/src/markdown/createAuthentication.ts @@ -13,7 +13,8 @@ export function createAuthentication(securitySchemes: SecuritySchemeObject) { if (!securitySchemes || !Object.keys(securitySchemes).length) return ""; const createAuthenticationTable = (securityScheme: any) => { - const { bearerFormat, flows, name, scheme, type } = securityScheme; + const { bearerFormat, flows, name, scheme, type, openIdConnectUrl } = + securityScheme; const createSecuritySchemeTypeRow = () => create("tr", { @@ -30,7 +31,7 @@ export function createAuthentication(securitySchemes: SecuritySchemeObject) { return create("tr", { children: [ - create("th", { children: `${flowType} OAuth Flow:` }), + create("th", { children: `OAuth Flow (${flowType}):` }), create("td", { children: [ guard(tokenUrl, () => @@ -91,12 +92,14 @@ export function createAuthentication(securitySchemes: SecuritySchemeObject) { create("td", { children: scheme }), ], }), - create("tr", { - children: [ - create("th", { children: "Bearer format:" }), - create("td", { children: bearerFormat }), - ], - }), + guard(bearerFormat, () => + create("tr", { + children: [ + create("th", { children: "Bearer format:" }), + create("td", { children: bearerFormat }), + ], + }) + ), ], }), }), @@ -115,23 +118,51 @@ export function createAuthentication(securitySchemes: SecuritySchemeObject) { }), ], }); + case "openIdConnect": + return create("div", { + children: [ + create("table", { + children: create("tbody", { + children: [ + createSecuritySchemeTypeRow(), + guard(openIdConnectUrl, () => + create("tr", { + children: [ + create("th", { children: "OpenID Connect URL:" }), + create("td", { children: openIdConnectUrl }), + ], + }) + ), + ], + }), + }), + ], + }); default: return ""; } }; - const formatTabLabel = (str: string) => { - const formattedLabel = str + const formatTabLabel = (key: string, type: string, scheme: string) => { + const formattedLabel = key .replace(/(_|-)/g, " ") .trim() .replace(/\w\S*/g, (str) => str.charAt(0).toUpperCase() + str.substr(1)) .replace(/([a-z])([A-Z])/g, "$1 $2") .replace(/([A-Z])([A-Z][a-z])/g, "$1 $2"); + const isOAuth = type === "oauth2"; + const isApiKey = type === "apiKey"; + const isHttpBasic = type === "http" && scheme === "basic"; + const isHttpBearer = type === "http" && scheme === "bearer"; + const isOpenId = type === "openIdConnect"; - const isOAuth = formattedLabel.toLowerCase().includes("oauth2"); - const isApiKey = formattedLabel.toLowerCase().includes("api"); + if (isOAuth) return `OAuth 2.0: ${key}`; + if (isApiKey) return `API Key: ${key}`; + if (isHttpBasic) return "HTTP: Basic Auth"; + if (isHttpBearer) return "HTTP: Bearer Auth"; + if (isOpenId) return `OpenID Connect: ${key}`; - return isOAuth ? "OAuth 2.0" : isApiKey ? "API Key" : formattedLabel; + return formattedLabel; }; return create("div", { @@ -141,12 +172,17 @@ export function createAuthentication(securitySchemes: SecuritySchemeObject) { id: "authentication", style: { marginBottom: "1rem" }, }), - create("Tabs", { + create("SchemaTabs", { + className: "openapi-tabs__security-schemes", children: Object.entries(securitySchemes).map( - ([schemeType, schemeObj]) => + ([schemeKey, schemeObj]) => create("TabItem", { - label: formatTabLabel(schemeType), - value: `${schemeType}`, + label: formatTabLabel( + schemeKey, + schemeObj.type, + schemeObj.scheme + ), + value: `${schemeKey}`, children: [ createDescription(schemeObj.description), createAuthenticationTable(schemeObj), diff --git a/packages/docusaurus-plugin-openapi-docs/src/markdown/index.ts b/packages/docusaurus-plugin-openapi-docs/src/markdown/index.ts index a69e5fc1b..a213e8b58 100644 --- a/packages/docusaurus-plugin-openapi-docs/src/markdown/index.ts +++ b/packages/docusaurus-plugin-openapi-docs/src/markdown/index.ts @@ -88,7 +88,7 @@ export function createInfoPageMD({ }: InfoPageMetadata) { return render([ `import ApiLogo from "@theme/ApiLogo";\n`, - `import Tabs from "@theme/Tabs";\n`, + `import SchemaTabs from "@theme/SchemaTabs";\n`, `import TabItem from "@theme/TabItem";\n`, `import Export from "@theme/ApiDemoPanel/Export";\n\n`, diff --git a/packages/docusaurus-plugin-openapi-docs/src/openapi/openapi.ts b/packages/docusaurus-plugin-openapi-docs/src/openapi/openapi.ts index 600e79002..0430e6d16 100644 --- a/packages/docusaurus-plugin-openapi-docs/src/openapi/openapi.ts +++ b/packages/docusaurus-plugin-openapi-docs/src/openapi/openapi.ts @@ -88,7 +88,7 @@ function createItems( const infoIdSpaces = openapiData.info.title.replace(" ", "-").toLowerCase(); const infoId = kebabCase(infoIdSpaces); - if (openapiData.info.description) { + if (openapiData.info.description || openapiData.info.title) { // Only create an info page if we have a description. const infoDescription = openapiData.info?.description; let splitDescription: any; diff --git a/packages/docusaurus-theme-openapi-docs/src/theme/ApiDemoPanel/SecuritySchemes/index.tsx b/packages/docusaurus-theme-openapi-docs/src/theme/ApiDemoPanel/SecuritySchemes/index.tsx index db9118057..04a482361 100644 --- a/packages/docusaurus-theme-openapi-docs/src/theme/ApiDemoPanel/SecuritySchemes/index.tsx +++ b/packages/docusaurus-theme-openapi-docs/src/theme/ApiDemoPanel/SecuritySchemes/index.tsx @@ -17,6 +17,10 @@ function SecuritySchemes(props: any) { if (selected === undefined) return null; + if (options[selected]?.[0]?.type === undefined) { + return null; + } + const selectedAuth = options[selected]; return (
@@ -24,11 +28,90 @@ function SecuritySchemes(props: any) {

Authorization

{selectedAuth.map((auth: any) => { + const isHttp = auth.type === "http"; const isApiKey = auth.type === "apiKey"; - const isBearer = auth.type === "http" && auth.key === "Bearer"; const isOauth2 = auth.type === "oauth2"; + const isOpenId = auth.type === "openIdConnect"; - if (isApiKey || isBearer) { + if (isHttp) { + if (auth.scheme === "bearer") { + const { name, key, type, scopes, ...rest } = auth; + return ( + +
+                  
+                    name:{" "}
+                    {name ?? key}
+                  
+                  
+                    type: 
+                    {type}
+                  
+                  {scopes && scopes.length > 0 && (
+                    
+                      scopes: 
+                      
+                        {auth.scopes.length > 0 ? auth.scopes.toString() : "[]"}
+                      
+                    
+                  )}
+                  {Object.keys(rest).map((k, i) => {
+                    return (
+                      
+                        {k}: 
+                        {rest[k]}
+                      
+                    );
+                  })}
+                
+
+ ); + } + if (auth.scheme === "basic") { + const { name, key, type, scopes, ...rest } = auth; + return ( + +
+                  
+                    name:{" "}
+                    {name ?? key}
+                  
+                  
+                    type: 
+                    {type}
+                  
+                  {scopes && scopes.length > 0 && (
+                    
+                      scopes: 
+                      
+                        {auth.scopes.length > 0 ? auth.scopes.toString() : "[]"}
+                      
+                    
+                  )}
+                  {Object.keys(rest).map((k, i) => {
+                    return (
+                      
+                        {k}: 
+                        {rest[k]}
+                      
+                    );
+                  })}
+                
+
+ ); + } return (
-                type: {auth.type}
                 
-                  name: {auth.name}
+                  name:{" "}
+                  {auth.name ?? auth.key}
+                
+                
+                  type: 
+                  {auth.type}
+                
+                
+                  in: 
+                  {auth.in}
                 
-                in: {auth.in}
+              
+
+ ); + } + + if (isApiKey) { + const { name, key, type, scopes, ...rest } = auth; + return ( + +
+                
+                  name:{" "}
+                  {name ?? key}
+                
+                
+                  type: 
+                  {type}
+                
+                {scopes && scopes.length > 0 && (
+                  
+                    scopes: 
+                    
+                      {auth.scopes.length > 0 ? auth.scopes.toString() : "[]"}
+                    
+                  
+                )}
+                {Object.keys(rest).map((k, i) => {
+                  return (
+                    
+                      {k}: 
+                      {rest[k]}
+                    
+                  );
+                })}
               
); } if (isOauth2) { + const { name, key, type, scopes, flows, ...rest } = auth; return (
                 
-                  type: {auth.type}
+                  name:{" "}
+                  {name ?? key}
+                
+                
+                  type: 
+                  {type}
                 
-                {Object.keys(auth.flows).map((flow) => {
-                  return flow: {flow};
+                {scopes && scopes.length > 0 && (
+                  
+                    scopes: 
+                    
+                      {auth.scopes.length > 0 ? auth.scopes.toString() : "[]"}
+                    
+                  
+                )}
+                {Object.keys(rest).map((k, i) => {
+                  return (
+                    
+                      {k}: 
+                      {rest[k]}
+                    
+                  );
                 })}
+                {flows && (
+                  
+                    
+                      flows: 
+                      {JSON.stringify(flows, null, 2)}
+                    
+                  
+                )}
+              
+
+ ); + } + + if (isOpenId) { + const { name, key, scopes, type, ...rest } = auth; + return ( + +
                 
-                  scopes: {auth.scopes.toString()}
+                  name:{" "}
+                  {name ?? key}
                 
+                
+                  type: 
+                  {type}
+                
+                {scopes && scopes.length > 0 && (
+                  
+                    scopes: 
+                    
+                      {auth.scopes.length > 0 ? auth.scopes.toString() : "[]"}
+                    
+                  
+                )}
+                {Object.keys(rest).map((k, i) => {
+                  return (
+                    
+                      {k}: 
+                      {rest[k]}
+                    
+                  );
+                })}
               
); diff --git a/packages/docusaurus-theme-openapi-docs/src/theme/styles.css b/packages/docusaurus-theme-openapi-docs/src/theme/styles.css index 5502e3cb8..d552d2ff3 100644 --- a/packages/docusaurus-theme-openapi-docs/src/theme/styles.css +++ b/packages/docusaurus-theme-openapi-docs/src/theme/styles.css @@ -479,3 +479,7 @@ .openapi__logo { width: 250px; } + +div:has(> ul.openapi-tabs__security-schemes) { + max-width: 100%; +}