Spring Boot

How to authorize Basic Auth requests in Spring Boot Swagger UI

We’re going to apply Basic Auth on API calls made from Swagger UI. OpenAPI allows us to provide security configuration for calling our documented endpoints and offers a few security schemes. Once we have our Spring Security configured and endpoints secured, we can show a project documentation to everyone, and allow visitors to provide credentials if they want to call a protected endpoint.

Prerequisites

Add Spring Security

Right now, the endpoints are available for everyone. We’re going to secure them.

Add Maven dependencies

First, we need to include the Maven dependencies for Spring Boot Starter Security and Spring security support module for springdoc-openapi in our pom.xml file:

<!-- pom.xml -->
…
<properties>
    <springdoc.version>1.5.9</springdoc.version>
    …
</properties>
…
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springdoc</groupId>
	<artifactId>springdoc-openapi-security</artifactId>
	<version>${springdoc.version}</version>
    </dependency>
…
</dependencies>
…

Next, we’re going to specify default credentials in our application.properties file:

# application.properties
spring.security.user.name=spring
spring.security.user.password=spring

If we were to start the application now, we would only have the default security configuration. It means that we would get the Spring Boot login page when calling any existing url:

Therefore, the Swagger UI page would be available only for a successfully authenticated user and all API endpoints would be protected. However, we want to show the API docs to everyone and only require authentication when someone wants to call the protected endpoints.

Allow anyone to see Swagger docs

We’re going to provide a custom configuration for the application security. We have to add the SecurityConfig.java file to our project and use the @Configuration annotation on it. What’s more, make sure that the class extends the WebSecurityConfigurerAdapter class so that we can override the configure(HttpSecurity http) method. Additionally, we’re going to add CorsFilter and exclude Swagger resources from the security:

package in.keepgrowing.springbootswaggeruibasicauth.shared.config.security;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private static final String[] SWAGGER_WHITELIST = {
            "/v3/api-docs/**",
            "/swagger-ui/**",
            "/swagger-ui.html",
    };

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .cors()
                .and()
                .authorizeRequests()
                .antMatchers(SWAGGER_WHITELIST).permitAll()
                .anyRequest().authenticated()
                .and()
                .httpBasic();
    }
}

As a result, anyone can view the documentation, but calling a secured endpoint will require providing valid credentials in a popup login form:

Add Basic Auth to Swagger UI

Our current OpenAPI configuration (details in the Easy OpenAPI 3 specification for your Spring Boot REST API post) looks like this:

package in.keepgrowing.springbootswaggeruibasicauth.shared.config.openapi;

import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class OpenApiConfig {

    @Bean
    public OpenAPI customOpenAPI(OpenApiProperties properties) {
        var openApi = new OpenAPI()
                .info(getInfo(properties));

        return openApi;
    }

    private Info getInfo(OpenApiProperties properties) {
        return new Info()
                .title(properties.getProjectTitle())
                .description(properties.getProjectDescription())
                .version(properties.getProjectVersion())
                .license(getLicense());
    }

    private License getLicense() {
        return new License()
                .name("Unlicense")
                .url("https://unlicense.org/");
    }
}

Apart from providing the usual API details (title and description from the OpenApiProperties class, license, etc.) we’re going to configure security. As we can read in the Swagger documentation:

Security is described using the securitySchemes and security keywords. You use securitySchemes to define all security schemes your API supports, then use security to apply specific schemes to the whole API or individual operations.

Authentication and Authorization: Describing Security

To understand what we want to achieve we need to take a look on the Swagger documentation for Basic Auth:

As we can see, we need to add the basic security scheme to the components and apply it to the entire API by listing it in the security. Let’s translate this to java code (and keep basicAuth as the arbitrary scheme name in our example as well):

package in.keepgrowing.springbootswaggeruibasicauth.shared.config.openapi;

import io.swagger.v3.oas.models.Components;
…
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
…
@Configuration
public class OpenApiConfig {

    private static final String SCHEME_NAME = "basicAuth";
    private static final String SCHEME = "basic";

    @Bean
    public OpenAPI customOpenAPI(OpenApiProperties properties) {
        return new OpenAPI()
                .info(getInfo(properties))
                .components(new Components()
                        .addSecuritySchemes(SCHEME_NAME, createSecurityScheme()))
                .addSecurityItem(new SecurityRequirement().addList(SCHEME_NAME));
    }
    …
    private SecurityScheme createSecurityScheme() {
        return new SecurityScheme()
                .name(SCHEME_NAME)
                .type(SecurityScheme.Type.HTTP)
                .scheme(SCHEME);
    }
}

Consequently, we can start the application and see the Authorize option on our Swagger UI page:

We have to click it and provide the correct credentials (spring:spring, as defined in my application.properties file) in order to call our secured endpoints:

Finally, we can call the API! Swagger will append the Authorization header to our requests as we can see in the curl section (and in the Headers view):

To sum up, the work done in this article is contained in the a7543dd30d12e23e10bb4fcb9e2deffc145e8b2e and 1f3ed0a5975a715b1aa4775d7d26e996101ee475 commits.

Learn more on securing Swagger UI

Photo by Artem Podrez from Pexels

little_pinecone

Recent Posts

Simplify the management of user roles in Spring Boot

Spring Security allows us to use role-based control to restrict access to API resources. However,…

3 years ago

Create a custom annotation to configure Spring Boot tests

A custom annotation in Spring Boot tests is an easy and flexible way to provide…

3 years ago

Keycloak with Spring Boot #4 – Simple guide for roles and authorities

Delegating user management to Keycloak allows us to better focus on meeting the business needs…

3 years ago

Keycloak with Spring Boot #3 – How to authorize requests in Swagger UI

Swagger offers various methods to authorize requests to our Keycloak secured API. I'll show you…

3 years ago

Keycloak with Spring Boot #2 – Spring Security instead of Keycloak in tests

Configuring our Spring Boot API to use Keycloak as an authentication and authorization server can…

3 years ago

Keycloak with Spring Boot #1 – Configure Spring Security with Keycloak

Keycloak provides simple integration with Spring applications. As a result, we can easily configure our…

3 years ago