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.
springdoc-openapi
read the Easy OpenAPI 3 specification for your Spring Boot REST API post.Right now, the endpoints are available for everyone. We’re going to secure them.
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.
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:
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
Authentication and Authorization: Describing SecuritysecuritySchemes
andsecurity
keywords. You usesecuritySchemes
to define all security schemes your API supports, then usesecurity
to apply specific schemes to the whole API or individual operations.
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.
Photo by Artem Podrez from Pexels
Spring Security allows us to use role-based control to restrict access to API resources. However,…
A custom annotation in Spring Boot tests is an easy and flexible way to provide…
Delegating user management to Keycloak allows us to better focus on meeting the business needs…
Swagger offers various methods to authorize requests to our Keycloak secured API. I'll show you…
Configuring our Spring Boot API to use Keycloak as an authentication and authorization server can…
Keycloak provides simple integration with Spring applications. As a result, we can easily configure our…