31

I am new to Swagger.

I am using Swagger UI to generate swagger documentation. I have two API calls. First call is to generate token based on user name and password. Second call needs token generated by first call.

How I set that token for second call using Swagger UI?

cassiomolin
  • 124,154
  • 35
  • 280
  • 359
Java P
  • 2,241
  • 6
  • 31
  • 45

8 Answers8

34

@ApiImplicitParams and @ApiImplicitParam should do the trick:

@GET
@Produces("application/json")
@ApiImplicitParams({
    @ApiImplicitParam(name = "Authorization", value = "Authorization token", 
                      required = true, dataType = "string", paramType = "header") })
public String getUser(@PathParam("username") String userName) {
    ...
}

From the documentation:

You may wish you describe operation parameters manually. This can be for various reasons, for example:

  • Using Servlets which don't use JAX-RS annotations.
  • Wanting to hide a parameter as it is defined and override it with a completely different definition.
  • Describe a parameter that is used by a filter or another resource prior to reaching the JAX-RS implementation.

The Swagger UI will be updated so you can send your token from there. No changes to HTML will be necessary.


Note: A while ago, when documenting a REST API with Swagger, I realized that just adding @ApiImplicitParam is not enough (even if you have only one parameter). Anyway, you must add @ApiImplicitParams too.

cassiomolin
  • 124,154
  • 35
  • 280
  • 359
  • how to get token from POST /oauth/token by adding parameters like username, password and grant type? because in swagger UI only parametters node is listed how to add custom parametters there? – Irfan Nasim Aug 18 '17 at 07:11
8

My configuration for 2.9.2 Swagger version to add Authorization on Swagger UI and send the Bearer token

    @Configuration
    public class SwaggerConfiguration{

        //...

          @Bean
          public Docket api(ServletContext servletContext) {
            return new Docket(DocumentationType.SWAGGER_2)...
                .securitySchemes(Arrays.asList(apiKey()))
                .securityContexts(Collections.singletonList(securityContext()));
          }

          private SecurityContext securityContext() {
            return SecurityContext.builder().securityReferences(defaultAuth()).forPaths(PathSelectors.regex("/.*")).build();
          }

          private List<SecurityReference> defaultAuth() {
            final AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
            final AuthorizationScope[] authorizationScopes = new AuthorizationScope[]{authorizationScope};
            return Collections.singletonList(new SecurityReference("Bearer", authorizationScopes));
          }

          private ApiKey apiKey() {
            return new ApiKey("Bearer", "Authorization", "header");
          }
    } 
RazvanParautiu
  • 2,805
  • 2
  • 18
  • 21
7

Another option is to add globalOperationParameters. It will add a field for authorization in every endpoint.

Define authorization header parameter:

Parameter authHeader = new ParameterBuilder()
  .parameterType("header")
  .name("Authorization")
  .modelRef(new ModelRef("string"))
  .build();

Add it to Docket configuration:

return new Docket(DocumentationType.SWAGGER_2)
    .select()
    .apis(...)
    .paths(...)
    .build()
    .apiInfo(...)
    .globalOperationParameters(Collections.singletonList(authHeader));

And it will look like this: enter image description here

Michal Lonski
  • 877
  • 1
  • 11
  • 20
4

There is a hack that might work by using responseInterceptor and requestInterceptor

First capture response of the the first API call using responseInterceptor and save the token (in the example in local storage), then use requestInterceptor to add the Authorization header with the saved token.

            const ui = SwaggerUIBundle({
               ...
                responseInterceptor:
                    function (response) {
                        if (response.obj.access_token) {
                            console.log(response.obj.access_token)
                            const token = response.obj.access_token;
                            localStorage.setItem("token", token)
                        }

                        return response;
                    },
                requestInterceptor:
                    function (request) {
                        console.log('[Swagger] intercept try-it-out request');
                        request.headers.Authorization = "Bearer " + localStorage.getItem("token");
                        return request;
                }
           }
Alex Efimov
  • 3,335
  • 1
  • 24
  • 29
  • Actually, I just tried this out and the responseInterceptor doesn't seem to be called for the auth-related responses. – Elias Dorneles May 24 '23 at 11:59
  • hmm. this might have changed, keep in mind the response is 4 years old, in the meanwhile swagger might have changed the workflow for auth, especially since this might cause auth token leaks. – Alex Efimov May 25 '23 at 12:06
  • yes, so, i found out that now there is an option `persistAuthorization` that when set to `true`, will cause the authorization data to be stored in localStorage. =) – Elias Dorneles May 25 '23 at 14:16
1

You would have to customise the swagger index page to accomplish that I believe.

You can make the input 'input_apiKey' hidden and add two inputs for username and password. Then you make an ajax call to update the hidden input with your token.

gsimoes
  • 1,011
  • 11
  • 12
1

This is an old question but this is how I solved it recently with version 2.7.0 for my JWT tokens

In your swagger configuration, add below SecurityConfiguration bean. Important part being leaving fifth argument empty or null.

@Bean
    public SecurityConfiguration securityInfo() {
        return new SecurityConfiguration(null, null, null, null, "", ApiKeyVehicle.HEADER,"Authorization","");
    }

Add securitySchemes(Lists.newArrayList(apiKey())) to your main Docket bean.

@Bean
    public Docket docket()
    {
        return new Docket(DocumentationType.SWAGGER_2).select()
            .....build().apiInfo(...).securitySchemes(Lists.newArrayList(apiKey()));
    }


    private ApiKey apiKey() {
        return new ApiKey("Authorization", "Authorization", "header");
    } 

Then in UI , you need to click on Authorize button and input "Bearer access_token" (for Authorization text box )where access_token is token provided by jWT token server.

Once this authorization is saved,that will become effective for all end points. Adding a separate text field for each end point looks very cumbersome.

Sabir Khan
  • 9,826
  • 7
  • 45
  • 98
  • Is this specific to Spring project? – Vikas Prasad Jul 09 '18 at 08:29
  • Yes, `Bean` is a Spring concept . Automatic configuration pick up is for Spring Boot. If you have Java config then caller to that config can be non - Spring framework but in this case, it is intended for Spring. – Sabir Khan Jul 09 '18 at 11:38
  • @SabirKhan How do I implement it without spring-fox? I'm using springdoc-openapi-ui (1.3.2). But still facing same issue. My spring boot version is 2.2.6. Hence needed to remove spring-fox. – iaL Apr 15 '20 at 19:34
  • @iaL:I am not sure ,will try to find & let you know if find anything useful. – Sabir Khan Apr 16 '20 at 13:04
0

Using SpringDoc with the springdoc-openapi-maven-plugin my option is to use a SwaggerConfig.Java:

@Configuration
public class SwaggerConfiguration  {
    @Bean
    public OpenAPI customOpenAPI(@Value("${project.version}") String appVersion) {
        OpenAPI openApi = new OpenAPI();
                openApi.info(
                    new Info()
                .title("Title Example")
                .version(appVersion)
                .description("Swagger server created using springdocs - a library for OpenAPI 3 with spring boot.")
                );

                openApi.components(
                        new Components().addSecuritySchemes("bearer-jwt",
                new SecurityScheme().type(SecurityScheme.Type.HTTP).scheme("bearer").bearerFormat("JWT")
                        .in(SecurityScheme.In.HEADER).name("Authorization"))
                );

                openApi.addSecurityItem(
                        new SecurityRequirement().addList("bearer-jwt", Arrays.asList("read", "write"))
                );

        return openApi;
    }
}
cWri
  • 1
0

Using Swagger UI 4, I've done this by configuring persistAuthorization and requestInterceptor Swagger UI configuration parameters:

  1. setting the persistAuthorization to true makes it storing the authorization data in browser's localStorage

  2. adding a requestInterceptor JS function that modify requests to pass along the accept_token.

Here is what my requestInterceptor function looks like:

function(request) {
    let authorize_json = window.sessionStorage.getItem('authorized')
    if (!authorize_json || authorize_json === '{}') {
        authorize_json = window.localStorage.getItem('authorized')
        if (!authorize_json) {
            return request
        }
    }

    // move from localStorage to sessionStorage, for better security
    window.localStorage.removeItem('authorized')
    window.sessionStorage.setItem('authorized', authorize_json)

    const persistedAuthData = JSON.parse(authorize_json)
    if (!persistedAuthData.oauth2) {
        return request
    }
    const access_token = persistedAuthData.oauth2.token.access_token
    request.headers['Authorization'] = 'Bearer ' + access_token
    return request
}
Elias Dorneles
  • 22,556
  • 11
  • 85
  • 107