Skip to content
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

Feature request: Add support for OAuth 2.0 authorization for Swagger UI #4036

Closed
2 tasks done
nlykkei opened this issue Mar 28, 2024 · 17 comments · Fixed by #4103
Closed
2 tasks done

Feature request: Add support for OAuth 2.0 authorization for Swagger UI #4036

nlykkei opened this issue Mar 28, 2024 · 17 comments · Fixed by #4103
Assignees
Labels

Comments

@nlykkei
Copy link
Contributor

nlykkei commented Mar 28, 2024

Use case

I want to protect and add authorization headers to requests sent using the Swagger UI, as endpoints are protected by an API Gateway REST Lambda authorizer:

https://docs.powertools.aws.dev/lambda/python/latest/core/event_handler/api_gateway/#enabling-swaggerui

Is this possible to achieve using the current Swagger UI implementation in powertools-lambda-python?

Solution/User Experience

I would like to provide configuration similar to how it's done for swagger-ui-py

Alternative solutions

No response

Acknowledgment

@leandrodamascena
Copy link
Contributor

Hello @nlykkei! We currently do not support authentication and authorization in our OpenAPI utility. We already have an issue open (#3662) for this same request and plan to work on it in the coming weeks. Do you mind if I close this issue and mention you in the one that's already open?

@leandrodamascena leandrodamascena added openapi-schema and removed triage Pending triage from maintainers labels Mar 28, 2024
@leandrodamascena leandrodamascena moved this from Triage to Pending customer in Powertools for AWS Lambda (Python) Mar 28, 2024
@nlykkei
Copy link
Contributor Author

nlykkei commented Mar 28, 2024

Thank you @leandrodamascena for your clarification.

Is it possible to implement myself using?:

swagger_base_url: str, optional
     The base url for the swagger UI. If not provided, we will serve a recent version of the Swagger UI.

I don't know much about Swagger UI, but it seems it support OAuth 2.0 configuration. Could that be included into the external bundles?

swagger_js = f"{swagger_base_url}/swagger-ui-bundle.min.js"
swagger_css = f"{swagger_base_url}/swagger-ui.min.css"

https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/

@leandrodamascena
Copy link
Contributor

Thank you @leandrodamascena for your clarification.

Is it possible to implement myself using?:

swagger_base_url: str, optional
     The base url for the swagger UI. If not provided, we will serve a recent version of the Swagger UI.

Unfortunately, no. This swagger_base is specifically for when customers wants to host in a external server the JS/CSS files required to render the Swagger UI.

I don't know much about Swagger UI, but it seems it support config for OAuth 2.0 configuration. Could that be included into the external bundles?

swagger_js = f"{swagger_base_url}/swagger-ui-bundle.min.js"
swagger_css = f"{swagger_base_url}/swagger-ui.min.css"

I'm afraid you can't do that. Swagger UI is a project designed to enable developers to import OpenAPI/Swagger files and display them interactively in the browser. To incorporate support for OAuth2.0 and other authentication methods, we must change our OpenAPI utility to inject the configuration into the OpenAPI file.

Let me talk with the team to see our timeline for implementing this. I'll return here as soon as I have updates.

Thanks

@nlykkei
Copy link
Contributor Author

nlykkei commented Mar 28, 2024

Thank you.

But what's the purpose of the Swagger UI OAuth 2.0 configuration options then?

https://swagger.io/docs/open-source-tools/swagger-ui/usage/oauth2/

Would that be configuration for fetching the OpenAPI spec itself?

Open swagger-initializer.js in your text editor and replace "https://petstore.swagger.io/v2/swagger.json" with the URL for your OpenAPI 3.0 spec.

What I need is a Swagger UI for the OpenAPI spec, optionally protected by OIDC, and with an interface like the following, where users press "SSO Login", which fetches a token for calling all defined API endpoints:

image

@leandrodamascena
Copy link
Contributor

My apologies for the misunderstanding. I realize now that what you're asking for is to protect the Swagger UI with OIDC/OAuth, rather than specific routes. Got it now.

However, I remain skeptical that this will work seamlessly without additional adjustments. We define the SwaggerUI at this line, and even if you bring your own JavaScript files and define initOAuth there, I doubt that var ui = SwaggerUIBundle(swaggerUIOptions) (here) will be able to read and embed specific OAuth configuration, at least without some hack.

The best approach here would be to introduce new parameters in the enable_swagger method, allowing customers to configure OAuth for SwaggerUI.

@leandrodamascena leandrodamascena changed the title Add support for OAuth 2.0 authorization for Swagger UI Feature request: Add support for OAuth 2.0 authorization for Swagger UI Mar 28, 2024
@leandrodamascena
Copy link
Contributor

I'm adding this issue to our backlog to work on it in the next sprints.

@leandrodamascena leandrodamascena moved this from Pending customer to Backlog in Powertools for AWS Lambda (Python) Mar 28, 2024
@nlykkei
Copy link
Contributor Author

nlykkei commented Mar 28, 2024

Thank you.

My apologies for the misunderstanding. I realize now that what you're asking for is to protect the Swagger UI with OIDC/OAuth, rather than specific routes. Got it now.

Actually, protecting the Swagger UI is not a requirement, but just a nice feature.

However, I want the Swagger UI to be able to execute the Authorization Code Grant Flow (OAuth 2.0) to acquire an access token for calling the listed API endpoints.

I hope, I'm clear now :)

@rubenfonseca
Copy link
Contributor

Making requests from the Swagger UI using OAuth 2.0 would be really good. Right now I'm not sure what's needed, so we need to investigate more, but it doesn't seem to be too hard. I can try to work on this next week if you want.

@rubenfonseca rubenfonseca self-assigned this Apr 8, 2024
@rubenfonseca
Copy link
Contributor

I'm starting to work on this now.

@rubenfonseca rubenfonseca moved this from Backlog to Working on it in Powertools for AWS Lambda (Python) Apr 8, 2024
@nlykkei
Copy link
Contributor Author

nlykkei commented Apr 8, 2024

I can help you out, if you need. I made some manually edits of the generated OpenAPI spec, then ran Swagger UI from a Docker container as follows:

docker run -p 3000:8080 -e OAUTH_CLIENT_ID=<client-id> -e OAUTH_APP_NAME="My App" -e OAUTH_SCOPES="api://<resource-id>/user_impersonation" -e OAUTH_USE_PKCE="true" -e SWAGGER_JSON=./openapi.yaml -v $(pwd):/openapi swaggerapi/swagger-ui

Swagger UI provides several ways to provide these arguments: config file, hard-coded, etc.

With securitySchemes defined, and security either specified locally for the operation or globally, the user can easily authenticate without having to enter any values itself, except names of scopes

@rubenfonseca
Copy link
Contributor

Awesome, thanks for this hints, I actually didn't had the full picture in my head how the Swagger UI would integrate with OAuth2, so your comment led me to learn all about securitySchemes :D I'll try to write something and will get back to you to get feedback.

@nlykkei
Copy link
Contributor Author

nlykkei commented Apr 9, 2024

Nice, if I can help with anything regarding the implementation, feel free to reach out. I would like to start contributing to the project myself :)

The tricky part is supplying the Swagger UI OAuth 2.0 configuration, which was provided as Docker environment variables above:

https://swagger.io/docs/open-source-tools/swagger-ui/usage/oauth2/

@rubenfonseca
Copy link
Contributor

rubenfonseca commented Apr 9, 2024

Oh I would love for you to contribute! 🎉 Here are my ideas:

  • don't worry about the Swagger UI for now, I have an idea to make it work easily
  • let's focus instead on adding support for securitySchemes and security on our OpenAPI generation

Right now the models are already there, but they are not used anywhere.

The OpenAPI spec says we can add security to both the top API declaration and individual operations.

So here's an idea (napkin programming here :P):

  • Add support for declaring securitySchemes on the top API declaration (here and here)
    • Maybe a new optional parameter security_schemes: Optional[List[SecurityScheme]]?
    • Make sure the generated schema now includes any securitySchemes (by adding it to the Components section)
oauth2_flows = OAuthFlows(authorizationCode=OAuthFlowAuthorizationCode(authorizationUrl="https://example.com/oauth/authorize", tokenUrl="https://example.com/oauth/token", scopes={"read": "Grants read access"})
app.get_openapi_schema(title="...", security_schemes=[OAuth2(flows=oauth2_flows)])
  • Add support for declaring a security on the same top API declaration. This would be interpreted by Swagger that it needs to apply to all operations.
    • Again, maybe a new optional parameter security: Optional[List[Dict[str, List[str]]]] (got the hint from here)
    • Bonus points: can we actually make sure that the key of each security object exists in the securitySchemes? This would avoid declaring security on a scheme that doesn't exist. Ideally we would do it at compile time (type checker) but not sure how far we can get
    • Make sure that the generated schema now includes the security field. Probably needs to be added here
app.get_openapi_schema(..., security=[{"OAuth2": ["admin"]}])

And finally, we need to add the same security support for each operation.

  • Start here and add a new security parameter. Make sure it's not the last parameter as the middleware functionality will stop working. middlewares always needs to be the last.
  • Apply the same changes the other HTTP operations, and the function signatures of all subclasses
  • And then make sure we can see the security being added to an operation
@app.get("/admin", security=[{"OAuth2": ["admin"]}])

Notice that this is just about generating the OpenAPI schema, not about enforcing any of those security schemas :D

Does any of this makes sense? Would you like to try it? :D If you're on Discord we can always have a chat if you ever get stuck.

@rubenfonseca
Copy link
Contributor

I've went ahead and started the implementation. Still some tasks to do (check the PR description), let me know if you want to take some!

@nlykkei
Copy link
Contributor Author

nlykkei commented Apr 10, 2024

Thank you @rubenfonseca. I commented on your other PR. Great job updating the docs with a clear explanation on usage.

I will get back to you tomorrow or Friday. I have been extremely busy at LEGO for the past 3 days, so I haven't had much time helping you out here

@github-project-automation github-project-automation bot moved this from Working on it to Coming soon in Powertools for AWS Lambda (Python) Apr 18, 2024
Copy link
Contributor

⚠️COMMENT VISIBILITY WARNING⚠️

This issue is now closed. Please be mindful that future comments are hard for our team to see.

If you need more assistance, please either tag a team member or open a new issue that references this one.

If you wish to keep having a conversation with other community members under this issue feel free to do so.

@github-actions github-actions bot added the pending-release Fix or implementation already in dev waiting to be released label Apr 18, 2024
Copy link
Contributor

This is now released under 2.37.0 version!

@github-actions github-actions bot removed the pending-release Fix or implementation already in dev waiting to be released label Apr 18, 2024
@leandrodamascena leandrodamascena moved this from Coming soon to Shipped in Powertools for AWS Lambda (Python) Apr 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Status: Shipped
3 participants