-
-
Notifications
You must be signed in to change notification settings - Fork 1k
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
Add securityDefinitions to openapi/swagger spec #1082
Comments
I've figured out this is enough in the swagger.json to have an "Authorize" button:
notice that |
Could you say more about what you did? Where is the |
you get the swagger.json from the root path of your backend (postgrest). I wrote a script to fetch my swagger.json from the backend and append the above mentioned part to it.
|
oh and I start a simplehttpserver with python to serve the swagger json from where I start the server (that directory). you have to enable CORS for swagger to work (fetch this file):
then you can run swagger (docker) and pass it the API_URL:
then hit localhost:9000 and you should see swaggerUI with an authorize button. |
Thanks! It would be nice for postgrest to have a flag and include this extra JSON content in the file it produces. |
yes either a flag or I say let's just put it in there anyway (hardcode it). it depends on the user if he wants to use authorization. the above snippet is enough to have it working. if you have endpoints which do not require an access token it will just be discarded anyway (because we are sending it as a query here). |
This would be an ideal addition to PostgREST so great suggestion @omani! The below def for securityDefinitions: {
"Bearer": {
" name": "Authorization",
"in": "header",
"type": "apiKey"
}
} Can anyone with knowledge of this codebase and/or Haskell chime in on the effort involved in to getting this implemented? |
This would be really handy. Perhaps PostGRest can see that |
@omani Your code worked for me man!! |
We use the swaggerapi/swagger-ui Docker image, and configure a responseInterceptor and a requestInterceptor to get the Authorization going. Dockerfile: FROM swaggerapi/swagger-ui
COPY conf/interceptors.js /usr/share/nginx/configurator/interceptors.js
RUN configurator=/usr/share/nginx/configurator; \
index="${configurator}/index.js"; \
interceptors="${configurator}/interceptors.js"; \
search='SwaggerUIBundle({'; \
replace="${search} $(cat ${interceptors} | tr -d '\n')"; \
sed -i "s|${search}|${replace}|g" "${index}" conf/interceptors.js: responseInterceptor: response => {
\n
const obj = response.obj;
if (obj \&\& obj.swagger) {
obj.securityDefinitions = {
AuthorizationHeader:
{ name: "Authorization"
, in: "header"
, type: "apiKey"
, description: 'Submit value "Bearer $token", then execute the Introspection request, then click Explore button (top right).'
}
};
obj.security = [{ AuthorizationHeader: [] }];
response.text = JSON.stringify(obj);
response.data = response.text;
}
\n
return response;
},
requestInterceptor: request => {
\n
window.AuthorizationHeader = window.AuthorizationHeader \|\| request.headers.Authorization;
request.headers.Authorization = request.headers.Authorization \|\| window.AuthorizationHeader;
\n
return request;
}, Or even without the Authorize button, actually executing a login request to log in, and saving the token in localStorage: conf/interceptors.js: responseInterceptor: response => {\n
if (response.url.endsWith('login') \&\& response.ok) {\n
const obj = response.obj[0] ? response.obj[0] : response.obj;\n
localStorage.setItem('Authorization', 'Bearer ' + obj.token);\n
location.reload();\n
}
if (response.status === 401 \|\| response.url.endsWith('logout')) {\n
localStorage.removeItem('Authorization');\n
location.reload();\n
}\n
return response;\n
},\n
requestInterceptor: request => {\n
request.headers.Authorization = localStorage.getItem('Authorization');\n
if (request.headers.Authorization === null) {\n
delete request.headers.Authorization;\n
}\n
return request;\n
}, |
I ended up with a slightly different solution to this problem. I wrote a server (an express app written in typescript) that sits between postgrest and swagger-ui and modifies the JSON returned by postgrest directly in the request: import cors from 'cors';
import express from 'express';
import fetch from 'node-fetch';
// CLI Usage
// API_URL=http://your_postgrest_url_and_port node ./dist/index.js
const port = process.env.PORT || 8080;
const apiUrl = process.env.API_URL!;
const authJson = {
'securityDefinitions':
{'jwt': {'type': 'apiKey', 'in': 'header', 'name': 'Authorization'}},
'security': [{'jwt': []}]
};
const app = express();
app.use(cors());
app.get('/', function(req: express.Request, res: express.Response) {
fetch(apiUrl)
.then((link) => link.json())
.then((swaggerJson) => res.json({...swaggerJson, ...authJson}));
});
app.listen(port, function() {
console.log(`http://localhost:${port} exposing API at ${apiUrl}`);
}); swagger-ui should now render a green "Authorize" button on the upper right part the page. When you specify the jwt value, make sure to explicitly prepend the string literal "Bearer " to the token (see OAI/OpenAPI-Specification#583). |
BTW since nobody mentioned since version 6.0 there is:
How to use:
Originally posted by @steve-chavez in #790 (comment) It's not yet in the documentation because:
Originally posted by @steve-chavez in PostgREST/postgrest-docs#239 (comment) |
@bwbroersma Can you elaborate on your comment? I'm not sure how that helps inject the required |
Standing on the shoulders of the great advise in this thread, I made an nginx proxy for the swagger json endpoint that inserts the code necessary for JWT to work in swagger. Check out the nginx config file. You can also pull the entire repository and run it on your own in docker. |
For my use-case, I happened to be running postgrest on supabase in kubernetes and was using nginx-ingress controller already to route into my swagger and postgrest internally. Since my ingress was already nginx running as a proxy pass, we only have to modify our existing ingress controller to insert the securityDefinitions. Here is what my ingress config looks like after making the changes @johnnylambada linked: ---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: supabase-ingress-rest
namespace: postgres # note! must be located in the same namespace as where service resides
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
# enable supplying jwt supabase api key to postgrest
nginx.ingress.kubernetes.io/configuration-snippet: |
sub_filter '"externalDocs"' '"securityDefinitions":{"JWT":{"type":"apiKey","in":"header","name":"Authorization"}, "supabaseApiKey": {"type":"apiKey","in":"header","name":"apiKey"}},"security":[{"JWT":[], "supabaseApiKey":[]}],"responses":{"UnauthorizedError":{"description":"Access token is missing or invalid"}},"externalDocs"';
sub_filter_types application/openapi+json;
sub_filter_once off;
spec:
rules:
- host: supabase.internalurl # the domain you want associated
http:
paths:
- path: /rest/v1(/|$)(.*)
pathType: Prefix
backend:
service:
name: supabase-supabase-rest # existing service
port:
number: 3000 # existing service port
ingressClassName: nginx
--- I am not sure how you would do it if you were using some other non-nginx based ingress, but you would instead probably use whatever equivalent does the same thing as these sub_filter configurations. Note one minor annoyance. For the JWT token with this setup you have to prepend Bearer in the field e.g. paste "Bearer my-token-here" with a space in between 'Bearer' and your token in the authorize field. I am not sure if there is a way to have that done for you already. I believe OpenAPI 3 fixes this issue or maybe there is a way to do it in OpenAPI 2 |
Still puzzled that there seems no easy way to just turn this on with a config option in docker compose or something. I'm using the docker images for postgrest and swagger-ui and don't see why I would set up yet another server to intercept or proxy something. I just want to turn on the authenticate button, which should be a simple config option or environment variable. |
@tvogt The "Authorize" button in Swagger should be available now after the latest update. To activate it, you'll need to add |
@laurenceisla fantastic! What's the parameter for the docker image? Or is that built by other people? |
@tvogt Use the env variable |
I was trying to add this version to try the new swagger authorization button, but I'm getting errors with any version superior to the stable 9.0.1: Any ideas what could it be? If I return to 9.0.1 docker image all works fine again. |
Hi,
it would be nice if we could include a securityDefinitions field to the swagger.json. By doing this we can have a custom header field in swagger-ui where you can paste your jwt.
right now I can't set an Authorization Bearer token with each request. but swagger-ui would show a button if some securityDefinitions is included in the openapi/swagger json spec I get from the root path.
or is there already any other way to do this?
The text was updated successfully, but these errors were encountered: