I have a Spring Boot App (2.7.10) and am using the Sprspringdoc-openapi-ui dependency (1.6.15). I have annotated my controller and it seems to be displaying correctly, however when I try and execute one of the endpoints which requires an Authorization Header, Swagger UI is not including it in the Authorization header and I get a 400 Bad Request: org.springframework.web.bind.MissingRequestHeaderException: Required request header 'Authorization' for method parameter type String is not present
Here is my controller class:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import io.swagger.v3.oas.annotations.OpenAPIDefinition;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.enums.SecuritySchemeIn;
import io.swagger.v3.oas.annotations.enums.SecuritySchemeType;
import io.swagger.v3.oas.annotations.info.Contact;
import io.swagger.v3.oas.annotations.info.Info;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.security.SecurityScheme;
import io.swagger.v3.oas.annotations.servers.Server;
import io.swagger.v3.oas.annotations.tags.Tag;
/**
* This controller will be invoked from the front end to be able to interact
* with the IAM Service<br>
* For some reason the swagger UI will not work with the getUserInfo request as its not passing in the Authorization header
*
* @author Hanif Rajabali
*/
@OpenAPIDefinition(
info = @Info(
title = "${api.info.title}",
version = "${api.info.version}",
description = "${api.info.description}",
termsOfService = "${api.info.termsOfService}",
contact = @Contact(name = "${api.info.contact.name}", url = "${api.info.contact.url}", email = "${api.info.contact.email}")
),
servers = { @Server(description = "${api.server.description}", url = "${api.server.url}") })
@SecurityScheme(name = "JWT Access Token", type = SecuritySchemeType.HTTP, scheme = "bearer", bearerFormat = "JWT", in = SecuritySchemeIn.HEADER)
@SecurityRequirement(name = "bearerAuth")
@Tag(name = "${api.tag.name}", description = "${api.tag.description}")
@CrossOrigin
@RestController
@RequestMapping(value = "${api.base-request-mapping}", produces = MediaType.APPLICATION_JSON_VALUE)
public class LoginController {
final Logger log = LoggerFactory.getLogger(this.getClass());
@Autowired
private LoginService loginService;
@Operation(
summary = "Retrieves User Attributes From an Authenticated User Within the IAM User Repository",
description = "The userInfo endpoint is an OpenID Connect (OIDC) userInfo endpoint. It responds with user attributes given an access tokens that the Token endpoint issued. The scopes in the users access token define the user attributes that the userInfo endpoint returns in its response. The openid scope must be one of the access token claims. Currently the authentication service provider is AWS Cognito",
security = @SecurityRequirement(name = "bearerAuth"),
parameters = @Parameter(
in = ParameterIn.HEADER,
name = "Authorization",
description = "Access Token",
required = true,
schema = @Schema(type = "string", format = "JWT"),
example = "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
)
)
@ApiResponses(
value = { @ApiResponse(responseCode = "200", description = "Successful Retrieval of User Attributes"),
@ApiResponse(
responseCode = "401",
description = "Unauthorized or Invalid Token",
content = { @Content(schema = @Schema(implementation = ApiErrorResponse.class)) }),
@ApiResponse(
responseCode = "500",
description = "Internal Server Error",
content = { @Content(schema = @Schema(implementation = ApiErrorResponse.class)) }) })
@GetMapping("/userinfo")
@ResponseBody
public ResponseEntity<LoginApiResponse<UserInfo>> getUserInfo(
@Parameter(in = ParameterIn.HEADER, name = "Authorization", required = true, schema = @Schema(type = "string", format = "Bearer"))
@RequestHeader(name = "Authorization", required = true) String accessToken) throws Exception {
UserInfo userInfo = this.loginService.getUserInfo(accessToken);
LoginApiResponse<?> apiResponse = this.loginService.createApiResponse(userInfo);
LoginApiResponse<UserInfo> userInfoResponse = (LoginApiResponse<UserInfo>) apiResponse;
return ResponseEntity.ok(userInfoResponse);
}
}