connexion icon indicating copy to clipboard operation
connexion copied to clipboard

Swagger UI's oauth authorization has wrong redirect address

Open dennisylyung opened this issue 5 years ago • 6 comments

Description

When I use the Swagger UI to get authorization from an Oauth server, the request includes a redirect location of http://localhost:3200/oauth2-redirect.html (the default redirect url of swagger ui), which is not accessible, as the connexion app I am running do not share the same host/port (I am using localhost:8080).

Expected Behaviour

I expect connexion to change the redirect url setting of swagger ui to a relative path adjusting to the actual running app.

Version

I am on connexion 2.2.0

dennisylyung avatar May 31 '19 04:05 dennisylyung

I have a similar issue, trying to access the swagger ui on production. Found a workaround though -- by changing the Swagger UI is served from to /, the redirect works as expected, as now the oauth2-redirect.html is in the right place:

    my_app = connexion.App(
        __name__,
        specification_dir=...,
        options={
            'swagger_url': '/',
        })

Of course that makes only sense if you don't have other things to serve from /.

tom-mi avatar Mar 11 '20 22:03 tom-mi

The redirect page is actually available as /ui/oauth2-redirect.html - it's just that it needs to send an absolute URL for the redirect and is unaware it needs to add the ui/. This is something that you can configure in the swagger-ui, but I'm still trying to find out if we can actually pass configuration options to the swagger UI via connexion.

SpoonMeiser avatar Oct 15 '20 15:10 SpoonMeiser

Yes, you can do this:

options = {
    "swagger_ui_config": {
        "oauth2RedirectUrl": "localhost:8080/ui/oauth2-redirect.html"
    }
}

app = connexion.FlaskApp(__name__, specification_dir='openapi/', options=options)

But it looks like you have to pass an absolute URL, which means you can't use flask to generate it with the correct server name

This is definitely something that connexion should handle.

SpoonMeiser avatar Oct 15 '20 15:10 SpoonMeiser

Thanks @SpoonMeiser - this saved me a lot of time - and thanks for posting a clear solution.

As I'm also using a base path I need to add this to the URL. So if my hostname is example.com, and I'm using a base-path of /data and a swagger URL of /api then the redirect URL becomes https://example.com/data/api/oauth2-redirect.html. I have these values in a Config module so my connexion options are setup like this...

# Option configuration for connexion/flask
#
# Set the oauth2 redirect URL.
# If we're using path-based API (i.e. hosted anywhere other than '/')
# or a swagger API not on this PATH then we need to provide an oauth2
# redirect URL that includes the base path and swagger path.
#   See problem and solution posted at
#   https://github.com/zalando/connexion/issues/968
#
# Here, for our deployment,
# API_HOSTNAME is typically 'example.com'
# API_BASE_PATH is typically '/data'
# SWAGGER_PATH is typically '/api'
_OAUTH2_REDIRECT_URL: str =\
    'https://%s%s%s/oauth2-redirect.html' % (Config.API_HOSTNAME,
                                             Config.API_BASE_PATH,
                                             Config.SWAGGER_PATH)
CONNEXION_OPTIONS: dict = {'swagger_url': Config.SWAGGER_PATH,
                           'swagger_ui_config': {
                             'oauth2RedirectUrl': _OAUTH2_REDIRECT_URL}}

# Start the Connexion app,
# identifying the base directory for the OpenAPI definition...
connexion_app = connexion.FlaskApp(__name__,
                                   specification_dir='openapi/',
                                   options=CONNEXION_OPTIONS)

...but, yes, it would be really handy of connexion could figure his out for itself!

I'm using connexion[swagger-ui] == 2.7.0

alanbchristie avatar Oct 26 '20 17:10 alanbchristie

Wouldn't redirecting with something like this by default workaround the problem?

@app.route('/oauth2-redirect.html')
def oauth2_redirect():
    args = "&".join(var + "=" + value for var, value in request.args.items())
    return redirect('/api/ui/oauth2-redirect.html?' + args, 302)

It seems to be a pretty simple workaround while the root cause is not tackled. It also doesn't need to know the current hostname to work.

Would there be any security concerns caused by doing it this way?

Governa avatar Jan 28 '21 00:01 Governa

Neat - but I'm also a Pod in a Kubernetes cluster and my Ingress directs all traffic at /data (in my case) to my Pod. All traffic on the base path (/) on the other hand goes to another Pod (another application in my cluster) as directed by a different Ingress.

I have a multiple applications served from the same hostname (example.com) so I cannot expect /oauth2-redirect.html to be sent to my application - it'll go to different application.

alanbchristie avatar Jan 29 '21 07:01 alanbchristie