SheppardDigital
SheppardDigital

Reputation: 3265

Spring boot + Swagger UI how to tell endpoint to require bearer token

I'm using Spring Boot to build a REST API. I've added Swagger-ui to handle documentation. I'm having a problem implementation the client authentication flow into swagger, the problem being I can get swagger-ui to authorise a supplied client-id(username) and client-secret(password) via basic auth, but swagger UI doesn't appear to be then applying to resulting access token to endpoint calls.

To confirm, my authorisation process; - Use basic auth to send base64 encoded username/password & grant_type=client_credentials to /oauth/token. Spring returns an access_token - On future API calls, use the supplied access_token as the bearer token

I think that the problem may be because I need to place something on each method in my controllers to tell swagger that the endpoint requires authentication and what type, but I can't find any clear documentation on how to do this, and I don't know if I need to apply any further changes to my swagger config.

Here's an example of a controller (with most methods removed to reduce size);

@Api(value="Currencies", description="Retrieve, create, update and delete currencies", tags = "Currencies")
@RestController
@RequestMapping("/currency")
public class CurrencyController {

    private CurrencyService currencyService;

    public CurrencyController(@Autowired CurrencyService currencyService) {
        this.currencyService = currencyService;
    }

    /**
     * Deletes the requested currency
     * @param currencyId the Id of the currency to delete
     * @return 200 OK if delete successful
     */
    @ApiOperation(value = "Deletes a currency item", response = ResponseEntity.class)
    @RequestMapping(value="/{currencyId}", method=RequestMethod.DELETE)
    public ResponseEntity<?> deleteCurrency(@PathVariable("currencyId") Long currencyId) {
        try {
            currencyService.deleteCurrencyById(currencyId);
        } catch (EntityNotFoundException e) {
            return new ErrorResponse("Unable to delete, currency with Id " + currencyId + " not found!").response(HttpStatus.NOT_FOUND);
        }

        return new ResponseEntity(HttpStatus.OK);
    }

    /**
     * Returns a single currency by it's Id
     * @param currencyId the currency Id to return
     * @return the found currency item or an error
     */
    @ApiOperation(value = "Returns a currency item", response = CurrencyResponse.class)
    @RequestMapping(value="/{currencyId}", method = RequestMethod.GET, produces = "application/json")
    public ResponseEntity<RestResponse> getCurrency(@PathVariable("currencyId") Long currencyId) {
        Currency currency = null;

        try {
            currency = currencyService.findById(currencyId);
        } catch (EntityNotFoundException e) {
            return new ErrorResponse("Currency with Id " + currencyId + " could not be found!").response(HttpStatus.NOT_FOUND);
        }

        return new CurrencyResponse(currency).response(HttpStatus.OK);
    }

    /**
     * Returns a list of all currencies available in the system
     * @return Rest response of all currencies
     */
    @ApiOperation(value = "Returns a list of all currencies ordered by priority", response = CurrencyListResponse.class)
    @RequestMapping(value="", method=RequestMethod.GET, produces="application/json")
    public ResponseEntity<RestResponse> getCurrencies() {
        return new CurrencyListResponse(currencyService.getAllCurrencies()).response(HttpStatus.OK);
    }

}

Here is my current swagger config;

@Configuration
@EnableSwagger2
public class SwaggerConfig extends WebMvcConfigurationSupport {

    @Bean
    public SecurityConfiguration security() {
        return SecurityConfigurationBuilder.builder()
                .clientId("12345")
                .clientSecret("12345")
                .scopeSeparator(" ")
                .useBasicAuthenticationWithAccessCodeGrant(true)
                .build();
    }

    @Bean
    public Docket productApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.xompare.moo.controllers"))
                .build()
                .securitySchemes(Arrays.asList(securityScheme()))
                .securityContexts(Arrays.asList(securityContext()))
                .apiInfo(metaData());

    }

    private SecurityContext securityContext() {
        return SecurityContext.builder()
                .securityReferences(Arrays.asList(new SecurityReference("spring_oauth", scopes())))
                .forPaths(PathSelectors.regex("/.*"))
                .build();
    }

    private AuthorizationScope[] scopes() {
        AuthorizationScope[] scopes = {
                new AuthorizationScope("read", "for read operations"),
                new AuthorizationScope("write", "for write operations") };
        return scopes;
    }

    public SecurityScheme securityScheme() {
        GrantType grantType = new ClientCredentialsGrant("http://localhost:8080/oauth/token");

        SecurityScheme oauth = new OAuthBuilder().name("spring_oauth")
                .grantTypes(Arrays.asList(grantType))
                .scopes(Arrays.asList(scopes()))
                .build();
        return oauth;
    }

    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("swagger-ui.html")
                .addResourceLocations("classpath:/META-INF/resources/");

        registry.addResourceHandler("/webjars/**")
                .addResourceLocations("classpath:/META-INF/resources/webjars/");
    }
}

Authentication via spring works perfectly at this point, my only problem is getting it working with Swagger UI.

Upvotes: 4

Views: 26369

Answers (2)

ppanagopo
ppanagopo

Reputation: 21

I think that you need to add "Bearer " in front of your key, just like it is shown at this post: Spring Boot & Swagger UI. Set JWT token

Upvotes: 2

SheppardDigital
SheppardDigital

Reputation: 3265

I managed to resolve this by reverting from swagger-ui version 2.8.0 to 2.7.0 after reading the contents of this link which suggested it was a problem with version 2.8.0

https://github.com/springfox/springfox/issues/1961

Upvotes: 0

Related Questions