Enable Authorize button in springdoc-openapi-ui for Bearer Token Authentication (JWT)

18,851

Solution 1

Define a global security scheme for OpenAPI 3.0 using annotation @io.swagger.v3.oas.annotations.security.SecurityScheme in a @Configuration bean:

@Configuration
@OpenAPIDefinition(info = @Info(title = "My API", version = "v1"))
@SecurityScheme(
    name = "bearerAuth",
    type = SecuritySchemeType.HTTP,
    bearerFormat = "JWT",
    scheme = "bearer"
)
public class OpenApi30Config {

}

Annotate each @RestController method requiring Bearer Token Authentication (JWT) with @io.swagger.v3.oas.annotations.Operation referencing the defined security scheme:

@Operation(summary = "My endpoint", security = @SecurityRequirement(name = "bearerAuth"))

Solution 2

I prefer to use bean initialization instead of annotation.

import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info; 
import io.swagger.v3.oas.models.security.SecurityRequirement; 
import io.swagger.v3.oas.models.security.SecurityScheme;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;

@Configuration
public class OpenApi30Config {

  private final String moduleName;
  private final String apiVersion;

  public OpenApi30Config(
      @Value("${module-name}") String moduleName,
      @Value("${api-version}") String apiVersion) {
    this.moduleName = moduleName;
    this.apiVersion = apiVersion;
  }

  @Bean
  public OpenAPI customOpenAPI() {
    final String securitySchemeName = "bearerAuth";
    final String apiTitle = String.format("%s API", StringUtils.capitalize(moduleName));
    return new OpenAPI()
        .addSecurityItem(new SecurityRequirement().addList(securitySchemeName))
        .components(
            new Components()
                .addSecuritySchemes(securitySchemeName,
                    new SecurityScheme()
                        .name(securitySchemeName)
                        .type(SecurityScheme.Type.HTTP)
                        .scheme("bearer")
                        .bearerFormat("JWT")
                )
        )
        .info(new Info().title(apiTitle).version(apiVersion));
  }
}

The line of code

.addSecurityItem(new SecurityRequirement().addList(securitySchemeName))

allows to add global security schema and to get rid of writing security to each @Operation of method.

Solution 3

If you want to avoid annotating each and every @Operation inside your @RestController with the security attribute, you can add this at class level affecting every operation of your controller.

Please don't forget that your configuration bean needs to be the same as in the other example:

@Configuration
@OpenAPIDefinition(info = @Info(title = "My API", version = "v1"))
@SecurityScheme(
    name = "bearerAuth",
    type = SecuritySchemeType.HTTP,
    bearerFormat = "JWT",
    scheme = "bearer"
)
public class OpenApi30Config {
}

Adding security requirement at class level

All you have to do is just use @SecurityRequirement(name = "bearerAuth") on those classes, where you would like to restrict the API calls. Note, that these annotations are inherited, so you can add them to any interface as well.

Create a marker interface with the required annotation:

@SecurityRequirement(name = "bearerAuth")
public interface SecuredRestController {
}

Add the marker interface to those controllers where you would like to apply the restriction to all operations, for example:

@RestController
@RequestMapping("/hello")
public class HelloController implements SecuredController {

    @GetMapping
    public String hello() {
        return "Hello World";
    }

    @GetMapping("/{name}")
    public String helloWithName(@PathVariable String name) {
        return "Hello " + name;
    }

}

You can do this without the marker interface just saying:

@RestController
@RequestMapping("/hello")
@SecurityRequirement(name = "bearerAuth")
public class HelloController {
...
}

Now you have both operations protected and requiring a JWT token. enter image description here

Adding security requirement at method level

As it was said in another post, you have to add the @SecurityRequirement to your @Operation annotation of your method.

@RestController
@RequestMapping("/hello")
public class HelloController {

    @GetMapping
    @Operation(summary = "My endpoint", security = @SecurityRequirement(name = "bearerAuth"))
    public String hello() {
        return "Hello World";
    }

    @GetMapping("/{name}")
    public String helloWithName(@PathVariable String name) {
        return "Hello " + name;
    }

}

This restricts only the first operation, but not the second. enter image description here

Share:
18,851
Eugene Khyst
Author by

Eugene Khyst

I am an Engineering Manager and Software Architect. My path: Software Engineer -> Tech Lead -> Solutions Architect -> VP of engineering running a department of 60+ people. I design robust software solutions, build engineering teams and establish an engineering culture. I have experience in improving an employer brand to boost the hiring of IT specialists and scaling teams to grow effective organizations. Favorite tech stack: Java, Spring Boot, TypeScript, Node.js, NestJS, Vue 3, Kafka, RabbitMQ, Docker, Kubernetes, Nginx, Prometheus, Grafana, Mocha, WebdriverIO, Appium, k6. Favorite methodologies: Agile, Kanban, Lean.

Updated on June 24, 2022

Comments

  • Eugene Khyst
    Eugene Khyst almost 2 years

    How to enable "Authorize" button in springdoc-openapi-ui (OpenAPI 3.0 /swagger-ui.html) for Bearer Token Authentication, for example JWT.

    What annotations have to be added to Spring @Controller and @Configuration classes?

    Authorize button

    Authorize form for Bearer Token Authentication