blueswen / mkdocs-swagger-ui-tag

A MkDocs plugin supports adding Swagger UI to the page.
https://blueswen.github.io/mkdocs-swagger-ui-tag/
MIT License
75 stars 7 forks source link

Is it possible to configure Swagger OAuth 2.0 authorization? #4

Closed robvanderleek closed 2 years ago

robvanderleek commented 2 years ago

Hi there 👋

In FastAPI there's the option swagger_ui_init_oauth to configure OAuth 2.0 authorization for Swagger. For example:

app = FastAPI(
    title='My API',
    description="My description",
    version="0.1.0",
    swagger_ui_init_oauth={
        "usePkceWithAuthorizationCodeGrant": True,
        "clientId": '****',
        "scopes": ['openid', 'email', 'groups'], },
)

Is it possible to set the parameters (or the complete dict) from swagger_ui_init_oauth using this plugin? I could not find it in the documentation but maybe I overlooked.

blueswen commented 2 years ago

Hi @robvanderleek

We don't have the feature to set the oauth parameters right now. But I can and the ui.initOAuth function and arguments into script with a simple approach. Do you think setting these parameters over html tag attribute like below is enough or need to add a dict to plugin options as global default?

<swagger-ui src="./demo/openapi-spec/sample.yaml" 
            usePkceWithAuthorizationCodeGrant="true"
            clientId="****"
            scopes="['openid', 'email', 'groups']" />
robvanderleek commented 2 years ago

If I check our Swagger page generated by FastAPI (where the OAuth authentication works) it contains this JS snippet in the HTML: image

So I guess it should indeed be enough to add the parameters in the HTML tag. Let me know if something is unclear or you want me to test a branch.

blueswen commented 2 years ago

We are supporting setting Swagger UI initOauth method in new version v0.4.0. You can check https://blueswen.github.io/mkdocs-swagger-ui-tag/demo/oauth2/ to see how to setting.

If there is something you think could be better please let me know. Thanks for the idea !

robvanderleek commented 2 years ago

Thanks for the quick implementation @blueswen !

I'm still struggling a bit with the configuration as somehow the redirect URI has oauth2-redirect.html appended while it should just return to the originating mkdocs location (site/api in my case).

Do you perhaps know what I'm missing here?

blueswen commented 2 years ago

Could you provide the plugin options in mkdocs.yml and the full swagger-ui tag in your markdown file? I am not very familiar with oauth2, maybe I mess something up.

robvanderleek commented 2 years ago

I'm also not an expert 😉

This is the tag I'm using in the Markdown:

<swagger-ui src="/openapi.json" clientId="****" usePkceWithAuthorizationCodeGrant="true" scopes="openid email groups"/>

And mkdocs.yml is pretty basic:

site_name: Self-Service API
site_dir: app/site
theme:
  name: material
  palette:
  - scheme: slate
    primary: light blue
    toggle:
      icon: material/lightbulb
      name: Switch to light mode
  - scheme: default
    primary: light blue
    toggle:
      icon: material/lightbulb-outline
      name: Switch to dark mode
  logo: assets/logo.png 
  favicon: assets/logo.png
  features:
    - toc.integrate 

plugins:
  - swagger-ui-tag
  - search

nav:
    - 'index.md'
    - 'auth.md'
    - 'api.md'
    - 'API Endpoints': '/docs/'

The last navigation entry is just the Swagger docs (I want to replace that one), the one before that points to the Markdown with the Swagger UI tag.

blueswen commented 2 years ago

Hum... Assume you are using FastAPI, maybe it is related to this FastAPI release and this pr? Then you are trying to make the Swagger UI in mkdocs has the exact same content as you posted before as follows right?

js

Besides could you provide the current js code about SwaggerUIBundle in your mkdocs swagger-ui iframe?

robvanderleek commented 2 years ago

Yes, I'm using FastAPI (version 0.75.2).

I posted indeed the Swagger UI JS code that works (but that's now opened on a separate tab, not an mkdocs iframe).

Below is the complete iframe content.

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Swagger UI</title>
  <link rel="stylesheet" type="text/css" href="[../assets/stylesheets/swagger-ui.css](http://localhost:3000/site/assets/stylesheets/swagger-ui.css)" />
  <link rel="stylesheet" type="text/css" id="slate-css" media="none" href="[../assets/stylesheets//swagger-ui-dark.css](http://localhost:3000/site/assets/stylesheets//swagger-ui-dark.css)" />
</head>

<body style="overflow:hidden;background: ;">
  <div id="swagger-ui"></div>
  <script src="[../assets/javascripts//swagger-ui-bundle.js](http://localhost:3000/site/assets/javascripts//swagger-ui-bundle.js)" charset="UTF-8"> </script>
  <script src="[../assets/javascripts//swagger-ui-standalone-preset.js](http://localhost:3000/site/assets/javascripts//swagger-ui-standalone-preset.js)" charset="UTF-8"> </script>
  <script>
    window.onload = function () {
      window.ui = SwaggerUIBundle({
        "dom_id": '#swagger-ui',
        presets: [
          SwaggerUIBundle.presets.apis,
          SwaggerUIStandalonePreset
        ],

        url: '/openapi.json',

    "docExpansion": "list",
    "filter": false,
    "tryItOutEnabled": false,
    "supportedSubmitMethods": [
        "get",
        "put",
        "post",
        "delete",
        "options",
        "head",
        "patch",
        "trace"
    ],
    "syntaxHighlight.theme": "agate"

      })

      window.ui.initOAuth({"clientId": "***", "scopes": "openid email groups", "usePkceWithAuthorizationCodeGrant": true})

      const scheme = parent.scheme
      if (scheme === "slate") {
          enable_dark_mode();
      }
    }

    const resize_ob = new ResizeObserver(function(entries) {
      parent.update_swagger_ui_iframe_height("e8ff2997");
    });

    // start observing for resize
    resize_ob.observe(document.querySelector("body"));

    enable_dark_mode = function(){
      document.getElementById("slate-css").media = ""
    }

    disable_dark_mode = function(){
      document.getElementById("slate-css").media = "none"
    }
  </script>
</body>

</html>

Let me know if you need more details, thanks for all the effort.

blueswen commented 2 years ago

Since version 0.4.1, we are using [site url]/assets/swagger-ui/oauth2-redirect.html as the default OAuth2 redirect URL. I also checked the redirect feature through a FastAPI OAuth2 example and Auth0, which seems good to me.

Let me know if there is anything I can do about this feature.

robvanderleek commented 2 years ago

Hi @blueswen

With version 0.4.1 the authorization works (!) but only when I explicitly configure site_url.

For completeness: if I don't configure site_url and access the documentation from http://localhost:3000/site/api the forward URL is:

https://****?response_type=code&client_id=****&redirect_uri=assets%2Fswagger-ui%2Foauth2-redirect.html&scope=...

If I add site_url: http://localhost:3000/site to mkdocs.yml the forward URL contains the correct host and path.

Depending on site_url is a bit challenging for us as the API is deployed in different environments.

blueswen commented 2 years ago

@robvanderleek Thanks for reporting. Didn't notice the case without site_url 😅.

We changed the default oauth2RedirectUrl logic in the new version 0.4.2, and the oauth2RedirectUrl absolute URL would be retrive from the relative URL according to the current URL like below: "oauth2RedirectUrl": new URL("../../assets/swagger-ui/oauth2-redirect.html",window.location.href).href

Hope this could fit your requests.

robvanderleek commented 2 years ago

Hi @blueswen 🙂

I can confirm it works now without explicitly setting site_url 🎉

For my use-case there's one small remaining issue related to the position of the OAuth popup dialog (it's centered in the iframe where the plain Swagger docs put it at the top). It's not really related to this so I could open a new issue for it, let me know (also I don't know if it's possible to change).

Thanks for putting in all the time and energy in fixing this issue!

blueswen commented 2 years ago

Great! I also learned more about OAuth2 when fixing this issue.

It would be great to open a new issue for the dialog issue.