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

Swagger OAUTH Proxy to avoid CORS issue #2796

Open
wants to merge 9 commits into
base: main
Choose a base branch
from

Conversation

fernando-oc
Copy link

Greetings,

While integrating Swagger with my application, I encountered issue #5104 related to authentication in the Swagger UI. To address this, I implemented a workaround that enables the application to act as a proxy between the OAuth provider (Keycloak, in this case) and the Swagger UI.

This pull request generalizes my solution into a configuration option for the springdoc-openapi dependency, enabling easier adoption in similar use cases.


Summary of Changes

This pull request introduces the following configuration options for enabling and managing an OAuth proxy in Swagger UI. Here we have some example values:

springdoc.swagger-ui.oauth-proxy.enabled=true
springdoc.swagger-ui.oauth-proxy.path=/forward-creds
springdoc.swagger-ui.oauth-proxy.oauth-token-uri=http://localhost:keycloak/realms/ch-nets-oauth-mock/protocol/openid-connect/token

How to Use

To enable this feature in your application, follow these steps:

1. Add the configuration shown in the Summary section in your application properties

In case your authentication provider adheres to OpenID Connect and you have defined the Spring Security OAuth2 client properties using issuer URI, then you could reference the token URI via the issuer URI:

springdoc.swagger-ui.oauth-proxy.oauth-token-uri=${spring.security.oauth2.client.provider.my-oauth-server.issuer-uri}/protocol/openid-connect/token

2. Add an OpenAPI Configuration Class

Create a configuration class with the following annotations and setup:

@OpenAPIDefinition(
    servers = { @Server(url = "/") }, 
    info = @Info(title = "Service APIs", description = "Example", version = "v1.0"))
@SecurityScheme(
    name = "BearerAuth", 
    type = SecuritySchemeType.OAUTH2, 
    flows = @OAuthFlows(clientCredentials = @OAuthFlow(
        tokenUrl = "${springdoc.swagger-ui.oauth-proxy.path}",
        scopes = { @OAuthScope(name = "openid", description = "openid scope") }
    ))
)
@Configuration
public class SwaggerUiConfiguration {
}

Mainly this is an example, the most important parts to take into account are inside the @SecurityScheme:

    name = "BearerAuth" 

and inside the @OAuthFlow referencing the proxy path:

    tokenUrl = "${springdoc.swagger-ui.oauth-proxy.path}",

3. Configure the Security Filter Chain

If the user has a SecurityConfig class, it might look like this:

@Configuration
public class SecurityConfig {

  @Autowired
  SwaggerOauthProxyProperties oauthProxyProperties;

  @Bean
  public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
        .sessionManagement(customizer -> customizer.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
        .csrf(AbstractHttpConfigurer::disable)
        .authorizeHttpRequests(customizer -> customizer
            .requestMatchers(HttpMethod.POST, oauthProxyProperties.getPath().getPath()).permitAll()
            .requestMatchers("/swagger-ui.html", "/swagger-ui/**", "/v3/api-docs/**", "/swagger-resources/**").permitAll()
            .anyRequest().authenticated());
    return http.build();
  }

}

To use this proxy the user needs to @Autowired the OauthProxy properties:

  @Autowired
  SwaggerOauthProxyProperties oauthProxyProperties;

And add add the proxy path to SecurityFilterChain to allow POST requests:

.requestMatchers(HttpMethod.POST, oauthProxyProperties.getPath().getPath()).permitAll()

Additional notes

  • I am aware that the Configuration files are Enabled via property binding, but I am not very familiar with this and I have used in the SwaggerConfig.java
@EnableConfigurationProperties(SwaggerOauthProxyProperties.class)
  • I have created my own SNAPSHOT of the springdoc-openapi to test the functionality locally and importing it to my project, but I did not create the tests in the dependency itself, as I have not done it before. If needed, please, let me know how to do them or which are the minimum requirements.
  • I have seen that there is always a reactive alternative for the code on spring-webflux, but for now I have only considered and tested this option with restClient.
  • There are further issues opened in the past related to this topic:
    issue #1650
    issue #2277

Please let me know if further details or changes are required. Sorry for the clumsiness, and thank you for considering this contribution! It is actually my first one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant