Skip to content

Commit 074b82b

Browse files
Merge pull request #101 from solo-io/charlesthebird/swaggerUiPrefillToken
Adds options to prefill swagger ui security schemes
2 parents 412c14d + 46a7b7c commit 074b82b

File tree

7 files changed

+146
-7
lines changed

7 files changed

+146
-7
lines changed

Dockerfile

+7-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,10 @@ ENV VITE_PORTAL_SERVER_URL=$VITE_PORTAL_SERVER_URL \
4646
VITE_APIS_IMAGE_URL=$VITE_APIS_IMAGE_URL \
4747
VITE_LOGO_IMAGE_URL=$VITE_LOGO_IMAGE_URL \
4848
VITE_COMPANY_NAME=$VITE_COMPANY_NAME \
49-
VITE_CUSTOM_PAGES=$VITE_CUSTOM_PAGES
49+
VITE_CUSTOM_PAGES=$VITE_CUSTOM_PAGES \
50+
VITE_SWAGGER_PREFILL_API_KEY=$VITE_SWAGGER_PREFILL_API_KEY \
51+
VITE_SWAGGER_PREFILL_OAUTH=$VITE_SWAGGER_PREFILL_OAUTH \
52+
VITE_SWAGGER_PREFILL_BASIC=$VITE_SWAGGER_PREFILL_BASIC
5053

5154
# Copy the server files, (this includes the UI build).
5255
WORKDIR /app
@@ -72,4 +75,7 @@ ENTRYPOINT VITE_PORTAL_SERVER_URL=$VITE_PORTAL_SERVER_URL \
7275
VITE_LOGO_IMAGE_URL=$VITE_LOGO_IMAGE_URL \
7376
VITE_COMPANY_NAME=$VITE_COMPANY_NAME \
7477
VITE_CUSTOM_PAGES=$VITE_CUSTOM_PAGES \
78+
VITE_SWAGGER_PREFILL_API_KEY=$VITE_SWAGGER_PREFILL_API_KEY \
79+
VITE_SWAGGER_PREFILL_OAUTH=$VITE_SWAGGER_PREFILL_OAUTH \
80+
VITE_SWAGGER_PREFILL_BASIC=$VITE_SWAGGER_PREFILL_BASIC \
7581
node ./bin/www

Makefile

+23-2
Original file line numberDiff line numberDiff line change
@@ -106,11 +106,32 @@ else ifneq ($(COMPANY_NAME),)
106106
endif
107107
#
108108
# CUSTOM PAGES
109-
ifneq ($(VITE_CUSTOM PAGES),)
110-
UI_ARGS += VITE_CUSTOM PAGES=$(VITE_CUSTOM_PAGES)
109+
ifneq ($(VITE_CUSTOM_PAGES),)
110+
UI_ARGS += VITE_CUSTOM_PAGES=$(VITE_CUSTOM_PAGES)
111111
else ifneq ($(CUSTOM_PAGES),)
112112
UI_ARGS += VITE_CUSTOM_PAGES=$(CUSTOM_PAGES)
113113
endif
114+
#
115+
# SWAGGER_PREFILL_API_KEY
116+
ifneq ($(VITE_SWAGGER_PREFILL_API_KEY),)
117+
UI_ARGS += VITE_SWAGGER_PREFILL_API_KEY=$(VITE_SWAGGER_PREFILL_API_KEY)
118+
else ifneq ($(SWAGGER_PREFILL_API_KEY),)
119+
UI_ARGS += VITE_SWAGGER_PREFILL_API_KEY=$(SWAGGER_PREFILL_API_KEY)
120+
endif
121+
#
122+
# SWAGGER_PREFILL_OAUTH
123+
ifneq ($(VITE_SWAGGER_PREFILL_OAUTH),)
124+
UI_ARGS += VITE_SWAGGER_PREFILL_OAUTH=$(VITE_SWAGGER_PREFILL_OAUTH)
125+
else ifneq ($(SWAGGER_PREFILL_OAUTH),)
126+
UI_ARGS += VITE_SWAGGER_PREFILL_OAUTH=$(SWAGGER_PREFILL_OAUTH)
127+
endif
128+
#
129+
# SWAGGER_PREFILL_BASIC
130+
ifneq ($(VITE_SWAGGER_PREFILL_BASIC),)
131+
UI_ARGS += VITE_SWAGGER_PREFILL_BASIC=$(VITE_SWAGGER_PREFILL_BASIC)
132+
else ifneq ($(SWAGGER_PREFILL_BASIC),)
133+
UI_ARGS += VITE_SWAGGER_PREFILL_BASIC=$(SWAGGER_PREFILL_BASIC)
134+
endif
114135

115136

116137

README.md

+7
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,13 @@ You can add these environment variables to a `.env.local` file in the `projects/
144144
When the website is opened, there should be two new pages in the top navigation bar.
145145
![custom pages example](readme_assets/custom-pages-navbar.png)
146146
The custom page's `path` property must be publicly accessible and end with `.md` or `.html`.
147+
- `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}}"]'`.
148+
- `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.
149+
- Converting the example object from the Swagger UI documentation to a string would result in the following:
150+
```
151+
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}'
152+
```
153+
- `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"]'`.
147154

148155
#### Environment Variables for PKCE Authorization Flow
149156

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
changelog:
2+
- type: FIX
3+
issueLink: https://github.com/solo-io/solo-projects/issues/6859
4+
description: >-
5+
Adds configuration options to pass through to Swagger UI's instance methods
6+
as defined here: https://github.com/swagger-api/swagger-ui/blob/master/docs/usage/configuration.md#instance-methods
7+
Including options to fill the Authorization Bearer token if the user is logged in.

projects/ui/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"name": "gloo-platform-portal-ui",
2+
"name": "dev-portal-starter",
33
"private": true,
44
"version": "0.0.13",
55
"type": "module",

projects/ui/src/Components/ApiDetails/shared/ApiSchema/swagger/SwaggerDisplay.tsx

+45-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
1-
import { useEffect, useState } from "react";
1+
import { useContext, useEffect, useState } from "react";
22
import SwaggerUIConstructor from "swagger-ui";
33
import "swagger-ui/dist/swagger-ui.css";
44
import { ApiVersionSchema } from "../../../../../Apis/api-types";
5-
import { swaggerConfigURL } from "../../../../../user_variables.tmplr";
5+
import { AuthContext } from "../../../../../Context/AuthContext";
6+
import {
7+
swaggerConfigURL,
8+
swaggerPrefillApiKey,
9+
swaggerPrefillBasic,
10+
swaggerPrefillOauth,
11+
} from "../../../../../user_variables.tmplr";
612
import { SwaggerDisplayContainer } from "./SwaggerDisplay.style";
713

814
const sanitize = (id: string) => id.replaceAll(".", "-");
@@ -14,6 +20,8 @@ export function SwaggerDisplay({
1420
apiVersionSpec: ApiVersionSchema | undefined;
1521
apiVersionId: string;
1622
}) {
23+
const { tokensResponse } = useContext(AuthContext);
24+
1725
// The sanitized dom_id, where all periods are replaced with dashes. This fixes issues where Swagger tries
1826
// doing a `querySelector` which fails, due to it treating the period as a class selector, and not part of the ID itself.
1927
const [sanitizedDomId, setSanitizedDomId] = useState<string>(
@@ -27,13 +35,47 @@ export function SwaggerDisplay({
2735
}, [apiVersionId, sanitizedDomId]);
2836

2937
useEffect(() => {
30-
SwaggerUIConstructor({
38+
const swaggerInstance = SwaggerUIConstructor({
3139
spec: apiVersionSpec,
3240
dom_id: `#display-swagger-${sanitizedDomId}`,
3341
withCredentials: true,
3442
deepLinking: true,
3543
configUrl: swaggerConfigURL !== "" ? swaggerConfigURL : undefined,
3644
});
45+
46+
// Here we pass through user supplied configuration for each of these Swagger UI instance methods:
47+
// https://github.com/swagger-api/swagger-ui/blob/master/docs/usage/configuration.md#instance-methods
48+
49+
// API KEY AUTH
50+
if (swaggerPrefillApiKey !== undefined) {
51+
let apiKeyValue = swaggerPrefillApiKey.apiKeyValue;
52+
if (!!tokensResponse?.access_token) {
53+
// Try to find & replace the "{{USER_TOKEN}}" string with this user's access token.
54+
// This is documented in the README.md.
55+
apiKeyValue = apiKeyValue.replace(
56+
"{{USER_TOKEN}}",
57+
tokensResponse.access_token
58+
);
59+
}
60+
swaggerInstance.preauthorizeApiKey(
61+
swaggerPrefillApiKey.authDefinitionKey,
62+
apiKeyValue
63+
);
64+
}
65+
66+
// OAUTH
67+
if (swaggerPrefillOauth !== undefined) {
68+
swaggerInstance.initOAuth(swaggerPrefillOauth);
69+
}
70+
71+
// BASIC AUTH
72+
if (swaggerPrefillBasic !== undefined) {
73+
swaggerInstance.preauthorizeBasic(
74+
swaggerPrefillBasic.authDefinitionKey,
75+
swaggerPrefillBasic.username,
76+
swaggerPrefillBasic.password
77+
);
78+
}
3779
}, [sanitizedDomId, apiVersionSpec]);
3880

3981
return (

projects/ui/src/user_variables.tmplr.ts

+56
Original file line numberDiff line numberDiff line change
@@ -190,3 +190,59 @@ export const customPages = JSON.parse(
190190
) as Array<CustomPage>;
191191
// TODO: Check the paths and if any overlap with the dev-portal-starter.
192192
// console.log("Loaded custom pages", customPages);
193+
194+
/**
195+
* This is optional. Check the README for usage.
196+
*/
197+
export const swaggerPrefillApiKey = (() => {
198+
const parsed = JSON.parse(
199+
templateString(
200+
"{{ tmplr.swaggerPrefillApiKey }}",
201+
insertedEnvironmentVariables?.VITE_SWAGGER_PREFILL_API_KEY,
202+
import.meta.env.VITE_SWAGGER_PREFILL_API_KEY,
203+
"[]"
204+
)
205+
) as [string, string] | [];
206+
return parsed.length === 2
207+
? {
208+
authDefinitionKey: parsed[0],
209+
apiKeyValue: parsed[1],
210+
}
211+
: undefined;
212+
})();
213+
214+
/**
215+
* This is optional. Check the README for usage.
216+
*/
217+
export const swaggerPrefillOauth = (() => {
218+
const parsed = JSON.parse(
219+
templateString(
220+
"{{ tmplr.swaggerPrefillOauth }}",
221+
insertedEnvironmentVariables?.VITE_SWAGGER_PREFILL_OAUTH,
222+
import.meta.env.VITE_SWAGGER_PREFILL_OAUTH,
223+
"{}"
224+
)
225+
);
226+
return Object.keys(parsed).length > 0 ? parsed : undefined;
227+
})();
228+
229+
/**
230+
* This is optional. Check the README for usage.
231+
*/
232+
export const swaggerPrefillBasic = (() => {
233+
const parsed = JSON.parse(
234+
templateString(
235+
"{{ tmplr.swaggerPrefillBasic }}",
236+
insertedEnvironmentVariables?.VITE_SWAGGER_PREFILL_BASIC,
237+
import.meta.env.VITE_SWAGGER_PREFILL_BASIC,
238+
"[]"
239+
)
240+
) as [string, string, string] | [];
241+
return parsed.length === 3
242+
? {
243+
authDefinitionKey: parsed[0],
244+
username: parsed[1],
245+
password: parsed[2],
246+
}
247+
: undefined;
248+
})();

0 commit comments

Comments
 (0)