Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds options to prefill swagger ui security schemes #101

Merged
8 changes: 7 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,10 @@ ENV VITE_PORTAL_SERVER_URL=$VITE_PORTAL_SERVER_URL \
VITE_APIS_IMAGE_URL=$VITE_APIS_IMAGE_URL \
VITE_LOGO_IMAGE_URL=$VITE_LOGO_IMAGE_URL \
VITE_COMPANY_NAME=$VITE_COMPANY_NAME \
VITE_CUSTOM_PAGES=$VITE_CUSTOM_PAGES
VITE_CUSTOM_PAGES=$VITE_CUSTOM_PAGES \
VITE_SWAGGER_PREFILL_API_KEY=$VITE_SWAGGER_PREFILL_API_KEY \
VITE_SWAGGER_PREFILL_OAUTH=$VITE_SWAGGER_PREFILL_OAUTH \
VITE_SWAGGER_PREFILL_BASIC=$VITE_SWAGGER_PREFILL_BASIC

# Copy the server files, (this includes the UI build).
WORKDIR /app
Expand All @@ -72,4 +75,7 @@ ENTRYPOINT VITE_PORTAL_SERVER_URL=$VITE_PORTAL_SERVER_URL \
VITE_LOGO_IMAGE_URL=$VITE_LOGO_IMAGE_URL \
VITE_COMPANY_NAME=$VITE_COMPANY_NAME \
VITE_CUSTOM_PAGES=$VITE_CUSTOM_PAGES \
VITE_SWAGGER_PREFILL_API_KEY=$VITE_SWAGGER_PREFILL_API_KEY \
VITE_SWAGGER_PREFILL_OAUTH=$VITE_SWAGGER_PREFILL_OAUTH \
VITE_SWAGGER_PREFILL_BASIC=$VITE_SWAGGER_PREFILL_BASIC \
node ./bin/www
25 changes: 23 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,32 @@ else ifneq ($(COMPANY_NAME),)
endif
#
# CUSTOM PAGES
ifneq ($(VITE_CUSTOM PAGES),)
UI_ARGS += VITE_CUSTOM PAGES=$(VITE_CUSTOM_PAGES)
ifneq ($(VITE_CUSTOM_PAGES),)
UI_ARGS += VITE_CUSTOM_PAGES=$(VITE_CUSTOM_PAGES)
else ifneq ($(CUSTOM_PAGES),)
UI_ARGS += VITE_CUSTOM_PAGES=$(CUSTOM_PAGES)
endif
#
# SWAGGER_PREFILL_API_KEY
ifneq ($(VITE_SWAGGER_PREFILL_API_KEY),)
UI_ARGS += VITE_SWAGGER_PREFILL_API_KEY=$(VITE_SWAGGER_PREFILL_API_KEY)
else ifneq ($(SWAGGER_PREFILL_API_KEY),)
UI_ARGS += VITE_SWAGGER_PREFILL_API_KEY=$(SWAGGER_PREFILL_API_KEY)
endif
#
# SWAGGER_PREFILL_OAUTH
ifneq ($(VITE_SWAGGER_PREFILL_OAUTH),)
UI_ARGS += VITE_SWAGGER_PREFILL_OAUTH=$(VITE_SWAGGER_PREFILL_OAUTH)
else ifneq ($(SWAGGER_PREFILL_OAUTH),)
UI_ARGS += VITE_SWAGGER_PREFILL_OAUTH=$(SWAGGER_PREFILL_OAUTH)
endif
#
# SWAGGER_PREFILL_BASIC
ifneq ($(VITE_SWAGGER_PREFILL_BASIC),)
UI_ARGS += VITE_SWAGGER_PREFILL_BASIC=$(VITE_SWAGGER_PREFILL_BASIC)
else ifneq ($(SWAGGER_PREFILL_BASIC),)
UI_ARGS += VITE_SWAGGER_PREFILL_BASIC=$(SWAGGER_PREFILL_BASIC)
endif



Expand Down
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,13 @@ You can add these environment variables to a `.env.local` file in the `projects/
When the website is opened, there should be two new pages in the top navigation bar.
![custom pages example](readme_assets/custom-pages-navbar.png)
The custom page's `path` property must be publicly accessible and end with `.md` or `.html`.
- `VITE_SWAGGER_PREFILL_API_KEY` - Prefills the Swagger UI authorization configuration for an API key or Bearer authorization scheme with the specified values. This can be set using the following format: `'["authDefinitionKey", "apiKeyValue"]'`, where "authDefinitionKey" is the key name of the security scheme to use from the API definition. In case of OpenAPI 3.0 Bearer scheme, `apiKeyValue` must contain just the token itself without the Bearer prefix. To use the logged in user's authorization token for the `apiKeyValue`, you may use the following syntax: `'["authDefinitionKey", "{{USER_TOKEN}}"]'`.
- `VITE_SWAGGER_PREFILL_OAUTH` - Prefills the Swagger UI authorization configuration for an OAuth server. This variable should be set to a serialized JSON object that is the OAuth2 configuration. See the [Swagger UI OAuth2 documentation](https://github.com/swagger-api/swagger-ui/blob/master/docs/usage/oauth2.md) for more information.
- Converting the example object from the Swagger UI documentation to a string would result in the following:
```
VITE_SWAGGER_PREFILL_OAUTH='{"clientId": "your-client-id","clientSecret": "your-client-secret-if-required","realm": "your-realms","appName": "your-app-name","scopeSeparator": " ","scopes": "openid profile","additionalQueryStringParams": {"test": "hello"},"useBasicAuthenticationWithAccessCodeGrant": true,"usePkceWithAuthorizationCodeGrant": true}'
```
- `VITE_SWAGGER_PREFILL_BASIC` - Prefills the Swagger UI authorization configuration for a Basic authorization scheme. This can be set using the following format: `'["authDefinitionKey", "username", "password"]'`.

#### Environment Variables for PKCE Authorization Flow

Expand Down
7 changes: 7 additions & 0 deletions changelog/v0.0.36/swagger-ui-prefill-token.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
changelog:
- type: FIX
issueLink: https://github.com/solo-io/solo-projects/issues/6859
description: >-
Adds configuration options to pass through to Swagger UI's instance methods
as defined here: https://github.com/swagger-api/swagger-ui/blob/master/docs/usage/configuration.md#instance-methods
Including options to fill the Authorization Bearer token if the user is logged in.
2 changes: 1 addition & 1 deletion projects/ui/package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "gloo-platform-portal-ui",
"name": "dev-portal-starter",
"private": true,
"version": "0.0.13",
"type": "module",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import { useEffect, useState } from "react";
import { useContext, useEffect, useState } from "react";
import SwaggerUIConstructor from "swagger-ui";
import "swagger-ui/dist/swagger-ui.css";
import { ApiVersionSchema } from "../../../../../Apis/api-types";
import { swaggerConfigURL } from "../../../../../user_variables.tmplr";
import { AuthContext } from "../../../../../Context/AuthContext";
import {
swaggerConfigURL,
swaggerPrefillApiKey,
swaggerPrefillBasic,
swaggerPrefillOauth,
} from "../../../../../user_variables.tmplr";
import { SwaggerDisplayContainer } from "./SwaggerDisplay.style";

const sanitize = (id: string) => id.replaceAll(".", "-");
Expand All @@ -14,6 +20,8 @@ export function SwaggerDisplay({
apiVersionSpec: ApiVersionSchema | undefined;
apiVersionId: string;
}) {
const { tokensResponse } = useContext(AuthContext);

// The sanitized dom_id, where all periods are replaced with dashes. This fixes issues where Swagger tries
// doing a `querySelector` which fails, due to it treating the period as a class selector, and not part of the ID itself.
const [sanitizedDomId, setSanitizedDomId] = useState<string>(
Expand All @@ -27,13 +35,47 @@ export function SwaggerDisplay({
}, [apiVersionId, sanitizedDomId]);

useEffect(() => {
SwaggerUIConstructor({
const swaggerInstance = SwaggerUIConstructor({
spec: apiVersionSpec,
dom_id: `#display-swagger-${sanitizedDomId}`,
withCredentials: true,
deepLinking: true,
configUrl: swaggerConfigURL !== "" ? swaggerConfigURL : undefined,
});

// Here we pass through user supplied configuration for each of these Swagger UI instance methods:
// https://github.com/swagger-api/swagger-ui/blob/master/docs/usage/configuration.md#instance-methods

// API KEY AUTH
if (swaggerPrefillApiKey !== undefined) {
let apiKeyValue = swaggerPrefillApiKey.apiKeyValue;
if (!!tokensResponse?.access_token) {
// Try to find & replace the "{{USER_TOKEN}}" string with this user's access token.
// This is documented in the README.md.
apiKeyValue = apiKeyValue.replace(
"{{USER_TOKEN}}",
tokensResponse.access_token
);
}
swaggerInstance.preauthorizeApiKey(
swaggerPrefillApiKey.authDefinitionKey,
apiKeyValue
);
}

// OAUTH
if (swaggerPrefillOauth !== undefined) {
swaggerInstance.initOAuth(swaggerPrefillOauth);
}

// BASIC AUTH
if (swaggerPrefillBasic !== undefined) {
swaggerInstance.preauthorizeBasic(
swaggerPrefillBasic.authDefinitionKey,
swaggerPrefillBasic.username,
swaggerPrefillBasic.password
);
}
}, [sanitizedDomId, apiVersionSpec]);

return (
Expand Down
56 changes: 56 additions & 0 deletions projects/ui/src/user_variables.tmplr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,3 +190,59 @@ export const customPages = JSON.parse(
) as Array<CustomPage>;
// TODO: Check the paths and if any overlap with the dev-portal-starter.
// console.log("Loaded custom pages", customPages);

/**
* This is optional. Check the README for usage.
*/
export const swaggerPrefillApiKey = (() => {
const parsed = JSON.parse(
templateString(
"{{ tmplr.swaggerPrefillApiKey }}",
insertedEnvironmentVariables?.VITE_SWAGGER_PREFILL_API_KEY,
import.meta.env.VITE_SWAGGER_PREFILL_API_KEY,
"[]"
)
) as [string, string] | [];
return parsed.length === 2
? {
authDefinitionKey: parsed[0],
apiKeyValue: parsed[1],
}
: undefined;
})();

/**
* This is optional. Check the README for usage.
*/
export const swaggerPrefillOauth = (() => {
const parsed = JSON.parse(
templateString(
"{{ tmplr.swaggerPrefillOauth }}",
insertedEnvironmentVariables?.VITE_SWAGGER_PREFILL_OAUTH,
import.meta.env.VITE_SWAGGER_PREFILL_OAUTH,
"{}"
)
);
return Object.keys(parsed).length > 0 ? parsed : undefined;
})();

/**
* This is optional. Check the README for usage.
*/
export const swaggerPrefillBasic = (() => {
const parsed = JSON.parse(
templateString(
"{{ tmplr.swaggerPrefillBasic }}",
insertedEnvironmentVariables?.VITE_SWAGGER_PREFILL_BASIC,
import.meta.env.VITE_SWAGGER_PREFILL_BASIC,
"[]"
)
) as [string, string, string] | [];
return parsed.length === 3
? {
authDefinitionKey: parsed[0],
username: parsed[1],
password: parsed[2],
}
: undefined;
})();
Loading