flask-restx icon indicating copy to clipboard operation
flask-restx copied to clipboard

Auth addition to flask-restx

Open j03INTHECLOUD opened this issue 5 years ago • 6 comments

Hey everyone, I was wondering if adding auth around endpoints is on the road map? Right now I see a lot of examples to just add a custom decorator functions to check api keys and other forms of auth. It seems pretty simplistic and I was wondering if flask-restx could provide a built in option?

Is this already a capability of flask-restx?

Solution if this does not exist: Add a built in decorator that you can add to each endpoint similar to @api.response or @api.expect. Then add a option in the Api class for the authorization key or something.

I would like your feedback on this idea and if I am thinking about this wrong.

j03INTHECLOUD avatar Mar 09 '20 18:03 j03INTHECLOUD

Hello,

You can already pass a decorator to the Api constructor that will be passed to each endpoint. This way, you can use your preferred third-party library/framework for the authentication part.

The Api constructor also provides a parameter that allow you to define custom fields/headers that should be forwarded to your endpoints when using the swagger-ui.

The parameters you might be interested in are authorizations and decorators as documented here.

ziirish avatar Mar 09 '20 20:03 ziirish

Is there any thought to solving https://github.com/noirbizarre/flask-restplus/issues/680 now that the corresponding issue in Swagger-UI (https://github.com/swagger-api/swagger-ui/issues/5348) has been solved?

The docs still say: "Using PKCE instead of Implicit Flow depends on https://github.com/swagger-api/swagger-ui/issues/5348"

nlarusstone avatar Apr 24 '20 15:04 nlarusstone

Any updates on this? I'll take a look through the code, but hoping someone has a straightforward answer

its-miller-time avatar Sep 10 '21 18:09 its-miller-time

no at moment, the swagger version on it already supports the PKCE, but we can´t set the variables in settings.

I did a workaround extending the swagger template (creating a template directory and create a file with the same name) and setting the PKCE required inputs,

example of my custom ui.initOAuth

ui.initOAuth({
    clientId: "{{ config.SWAGGER_UI_OAUTH_CLIENT_ID }}",
    realm: "{{ config.SWAGGER_UI_OAUTH_REALM }}",
    appName: "{{ config.SWAGGER_UI_OAUTH_APP_NAME }}",
    // Auth0 extra query strings for PCKE
    additionalQueryStringParams: {
      audience: "{{ config.SWAGGER_UI_OAUTH_APP_AUDIENCE }}", # Custom settings created by me 
      response_mode: 'query'  # fixed value works for me, but its depend of you OAuth2 config
    },
    usePkceWithAuthorizationCodeGrant: true // This set to true
})

maybe could help you @its-miller-time

I will work in a PR :)

jrnp97 avatar Sep 10 '21 19:09 jrnp97

Is there any update on this? @jrnp97 thanks for the headsup on the override! It works a treat in the meantime

euan-cowie avatar Oct 13 '21 00:10 euan-cowie

@jrnp97 @euan-cowie Could you please explain a bit more about what is the workaround explained in your previous comments?

Right now, I was trying the below in flask-restx

authorizations = {
    'oauth2': {
        'type': 'oauth2',
        'flow': 'accessCode',
        'clientId': "some-client-id",
        'clientSecret': "some-client-secret",
        'authorizationUrl': 'https://<auth-server-host-name>/oauth2/<auth-server-id>/v1/authorize?code_challenge=nOoaE86Z__cUR1Js04dFwzqD6cqvmnzlQ4xR9KNZDIU&code_challenge_method=S256&response_mode=query',
        'tokenUrl': 'https://<auth-server-host-name>/oauth2/<auth-server-id>/v1/token?code_verifier=209a9d4d49f39b64f2c908a848bd30ddcb9db812caf89017f8cbe8b9ee493e1e',
        'scopes': {
            'profile': 'Get identity',
        }
    }
}

api_v1_blueprint = Blueprint("api", __name__, url_prefix="/api/v1")
api = Api(api_v1_blueprint, authorizations=authorizations)

This is not working for me. I am getting the below error. Would really appreciate any clues on why this is happening. One guess I have is, in my okta-auth-server the application type that I have is "Web applicaiton", and as per this post, it should be "single page applicaiton" instead. Did not try this one yet due to lack of permission to change that.

Auth error Error: Unauthorized, error: invalid_client, description: Client authentication failed. Either the client or the client credentials are invalid.

UPDATEs: After trying out a couple of things, found the complete configs for "authcode + pkce" flow using "swagger UI" and "flask-restx". (I was using okta auth server, should be same for others)

  1. While creating an application in auth-server, we need to make sure to choose the application type as "Single Page Applicaiton". If we select any other application type, okta has configs that says invalid client credentials even if we send empty client_secret.

  2. To redirect the received auth_code from 1st authorization request and send that to accessToken request. This has to handled by the client. In our case, client is swagger, swagger has "oauth2-redirect.html", we have to see what is the redirect uri mentioned in the 1st request for authorization. And then make sure that "oauth2-redirect.html" file is rendered on that redirect uri. This we can taken care automatically if we have set app.config.SWAGGER_UI_OAUTH_CLIENT_ID = 'MyClientId' in the app, because mentioning redirect url is done using and if block with check on presence of above config var in swagger-ui.html file. or we can do manually if not working.

  3. Now, about the workaround for using PKCE query params automatically in our requests to authserver. Thanks, @jrnp97 for sharing the workaround. Created a template folder as per the structure of the project, and placed a copy of swagger-ui.html file there. Configured the ui.initOauth block by adding usePkceWithAuthorizationCodeGrant like below

        {% if config.SWAGGER_UI_OAUTH_CLIENT_ID -%}
        ui.initOAuth({
            clientId: "{{ config.SWAGGER_UI_OAUTH_CLIENT_ID }}",
            realm: "{{ config.SWAGGER_UI_OAUTH_REALM }}",
            appName: "{{ config.SWAGGER_UI_OAUTH_APP_NAME }}",
            additionalQueryStringParams: {
                response_mode: 'query'
            },
            usePkceWithAuthorizationCodeGrant: true // This set to true
        })

Again you can see that, its inside an if block, so make sure to set app.config.SWAGGER_UI_OAUTH_CLIENT_ID = clientId while setting app config properties.

While making sure that the above things are setup. I setup the authorizations as suggested in official doc https://flask-restx.readthedocs.io/en/latest/swagger.html

app = Flask(__name__)
app.config.SWAGGER_UI_OAUTH_CLIENT_ID = clientId
authorizations = {
    'oauth2': {
        'type': 'oauth2',
        'flow': 'accessCode',
        'clientId': "<clientId>",
        'authorizationUrl': '<auth_url>',
        'tokenUrl': 'token_url',
        'scopes': {
            'openid': 'Get ID token',
        }
    }
}

api_v1_blueprint = Blueprint("api", __name__, url_prefix="/api/v1")
api = Api(api_v1_blueprint, authorizations=authorizations)

Mukesh-Singh-exp avatar Aug 30 '23 20:08 Mukesh-Singh-exp