Security Top

I just announced the new Learn Spring Security course, including the full material focused on the new OAuth2 stack in Spring Security 5:

>> CHECK OUT THE COURSE

1. Overview

Springdoc-OpenAPI is a library that automates the service documentation generation for Spring Boot applications based on the OpenAPI 3 specification.

Interacting with our APIs through a user interface without implementing one can be handy. Therefore let's see how we consume the endpoints if authorization is involved.

In this tutorial, we'll learn how to manage secure endpoint access in Springdoc with Form Login and Basic Authentication using Spring Security.

2. Project Setup

We'll set up a Spring Boot web application exposing an API secured by Spring Security and have the documentation generated with Springdoc.

2.1. Dependencies

Let's declare the required maven dependencies for our project. Firstly, we'll add springdoc-openapi-ui, responsible for integrating with Swagger-UI and providing the visual tool accessible by default at:

http://localhost:8080/swagger-ui.html

Secondly, adding the springdoc-openapi-security module offers support for Spring Security:

<dependency>
     <groupId>org.springdoc</groupId>
     <artifactId>springdoc-openapi-ui</artifactId>
     <version>1.6.13</version>
</dependency>
<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-security</artifactId>
    <version>1.6.13</version>
</dependency>

2.2. Sample API

For this article, we'll implement a dummy REST Controller as the source for generating documentation with Springdoc. In addition, we'll exemplify the means of authenticating to interact with FooController‘s protected endpoints via Swagger-UI.

@RestController
@RequestMapping(value = "foos", produces = MediaType.APPLICATION_JSON_VALUE)
@OpenAPIDefinition(info = @Info(title = "Foos API", version = "v1"))
public class FooController {

    @GetMapping(value = "/{id}")
    public FooDTO findById(@PathVariable("id") final Long id) {
        return new FooDTO(randomAlphabetic(STRING_LENGTH));
    }

    @GetMapping
    public List<FooDTO> findAll() {
        return Lists.newArrayList(new FooDTO(randomAlphabetic(STRING_LENGTH)),
          new FooDTO(randomAlphabetic(STRING_LENGTH)), new FooDTO(randomAlphabetic(STRING_LENGTH)));
    }

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public FooDTO create(@RequestBody final FooDTO fooDTO) {
        return fooDTO;
    }
}

2.3. User Credentials

We'll make use of Spring Security's in-memory authentication to register our test user credentials:

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth, PasswordEncoder passwordEncoder) throws Exception {
    auth.inMemoryAuthentication()
      .withUser("user")
      .password(passwordEncoder.encode("password"))
      .roles("USER");
}

3. Form-Based Login Authentication

Let's look at how we can authenticate to interact with our form-based login-secured documented endpoints.

3.1. Security Configuration

Here we're defining the security configuration to authorize requests with Form Login:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
      .csrf().disable()
      .authorizeRequests()
      .antMatchers("/v3/api-docs/**",
        "/swagger-ui/**",
        "/swagger-ui.html").permitAll()
      .anyRequest().authenticated()
      .and()
      .formLogin()
      .defaultSuccessUrl("/foos");
    return http.build();
}

3.2. Login Documentation

By default, the framework-provided login endpoint is not documented. Therefore we need to make it visible by setting the corresponding configuration property. Moreover, useful configuration properties can be found in the library's documentation:

springdoc.show-login-endpoint=true

Afterward, Springdoc will detect the configured Spring Security's Form Login and generate the documentation in Swagger-UI. As so, it will add the /login endpoint with the username and password request parameters and the specific application/x-www-form-urlencoded request body type:

login endpoint swagger ui

After authenticating, we're set to call the secured FooController endpoints. Also, we get the response from the /foos endpoint for the successful login because of the defaultSucccesfulUrl security configuration:

successful login swagger

3.3. Logout Documentation

Being able to log out facilitates user switching in Swagger-UI, which can be helpful. For example, when applying role-based API authorization.

Springdoc does not offer a way of auto-detecting the logout endpoint like for login. In this case, we'll need to define a fake REST Controller exposing a post-request mapping for the /logout path. However, we don't need to add implementation since Spring Security will intercept and process the request:

@RestController
public class LogoutController {

    @PostMapping("logout")
    public void logout() {}
}

By adding LogoutController, the library will generate documentation and make logout available in Swagger-UI:

Logout endpoint in Swagger-UI

4. Basic Authentication

When dealing with Basic Authentication secured endpoints, we don't need to invoke login directly. On the other hand, OpenAPI supports a set of standard security schemes, including Basic Auth, and we can configure Springdoc accordingly.

4.1. Security Configuration

Simple security configuration to protect endpoints using Basic Authentication:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
      .csrf().disable()
      .authorizeRequests()
      .antMatchers("/v3/api-docs/**",
        "/swagger-ui/**",
        "/swagger-ui.html").permitAll()
      .anyRequest().authenticated()
      .and()
      .httpBasic();
    return http.build();
}

4.2. Springdoc Security Scheme

To configure the OpenAPI security scheme, we need to provide a @SecurityScheme annotation-based configuration:

@Configuration
@SecurityScheme(
  type = SecuritySchemeType.HTTP,
  name = "basicAuth",
  scheme = "basic")
public class SpringdocConfig {}

And then, we'll also have to annotate our FooController with @SecurityRequirement(name = “basicAuth”). We could apply this annotation at the method level if we want only to secure some endpoints or use different schemes:

@RestController
@OpenAPIDefinition(info = @Info(title = "Foos API", version = "v1"))
@SecurityRequirement(name = "basicAuth")
@RequestMapping(value = "foos", produces = MediaType.APPLICATION_JSON_VALUE)
public class FooController {
    ...
}

Hence, the Authorize button will be available in Swagger-UI:

Authorize button in Swagger-UI

Then, we can provide our user credentials in the form:

Authorize for Basic Auth

Subsequently, when invoking any FooController endpoint, the Authorization header with the credentials will be included in the request, as shown in the generated curl command. Thus, we'll be authorized to execute requests:

Authorization Header for Basic Auth

5. Conclusion

In this article, we learned how to configure authentication in Springdoc for accessing protected endpoints via generated documentation in Swagger-UI. Initially, we went through a form-based login setup. And then, we configured the security scheme for Basic Authentication.

The project implementation for this tutorial is available over on GitHub.

Security bottom

I just announced the new Learn Spring Security course, including the full material focused on the new OAuth2 stack in Spring Security 5:

>> CHECK OUT THE COURSE
Security footer banner
Comments are closed on this article!