134

My project has Spring Security. Main issue: Not able to access swagger URL at http://localhost:8080/api/v2/api-docs. It says Missing or invalid Authorization header.

Screenshot of the browser window My pom.xml has the following entries

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.4.0</version>
</dependency>

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.4.0</version>
</dependency>

SwaggerConfig :

@Configuration
@EnableSwagger2
public class SwaggerConfig {

@Bean
public Docket api() {
    return new Docket(DocumentationType.SWAGGER_2).select()
            .apis(RequestHandlerSelectors.any())
            .paths(PathSelectors.any())
            .build()
            .apiInfo(apiInfo());
}

private ApiInfo apiInfo() {
    ApiInfo apiInfo = new ApiInfo("My REST API", "Some custom description of API.", "API TOS", "Terms of service", "myeaddress@company.com", "License of API", "API license URL");
    return apiInfo;
}

AppConfig:

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = { "com.musigma.esp2" })
@Import(SwaggerConfig.class)
public class AppConfig extends WebMvcConfigurerAdapter {

// ========= Overrides ===========

@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(new LocaleChangeInterceptor());
}

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

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

web.xml entries:

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
        com.musigma.esp2.configuration.AppConfig
        com.musigma.esp2.configuration.WebSecurityConfiguration
        com.musigma.esp2.configuration.PersistenceConfig
        com.musigma.esp2.configuration.ACLConfig
        com.musigma.esp2.configuration.SwaggerConfig
    </param-value>
</context-param>

WebSecurityConfig:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@ComponentScan(basePackages = { "com.musigma.esp2.service", "com.musigma.esp2.security" })
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity
        .csrf()
            .disable()
        .exceptionHandling()
            .authenticationEntryPoint(this.unauthorizedHandler)
            .and()
        .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
        .authorizeRequests()
            .antMatchers("/auth/login", "/auth/logout").permitAll()
            .antMatchers("/api/**").authenticated()
            .anyRequest().authenticated();

        // custom JSON based authentication by POST of {"username":"<name>","password":"<password>"} which sets the token header upon authentication
        httpSecurity.addFilterBefore(loginFilter(), UsernamePasswordAuthenticationFilter.class);

        // custom Token based authentication based on the header previously given to the client
        httpSecurity.addFilterBefore(new StatelessTokenAuthenticationFilter(tokenAuthenticationService), UsernamePasswordAuthenticationFilter.class);
    }
}
djm.im
  • 3,295
  • 4
  • 30
  • 45
shubhendu_shekhar
  • 1,373
  • 2
  • 9
  • 13
  • Use the security configuration mentioned on [Cannot open Swagger UI in its Version 3 in my Spring Boot Example](https://stackoverflow.com/questions/73073519/cannot-open-swagger-ui-in-its-version-3-in-my-spring-boot-example) page. – Murat Yıldız Feb 07 '23 at 22:39

15 Answers15

232

Adding this to your WebSecurityConfiguration class should do the trick.

@Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/v2/api-docs",
                                   "/configuration/ui",
                                   "/swagger-resources/**",
                                   "/configuration/security",
                                   "/swagger-ui.html",
                                   "/webjars/**");
    }

}
shashwat
  • 7,851
  • 9
  • 57
  • 90
Stijn Maller
  • 2,965
  • 1
  • 18
  • 8
  • 15
    If you use swagger-ui you need something like this: .antMatchers("/v2/api-docs", "/configuration/ui", "/swagger-resources", "/configuration/security", "/swagger-ui.html", "/webjars/**","/swagger-resources/configuration/ui","/swagger-ui.html").permitAll() – Daniel Martín Jan 23 '17 at 18:07
  • 2
    In my case this rule is working: .antMatchers("/v2/api-docs", "/configuration/ui", "/swagger-resources", "/configuration/security", "/swagger-ui.html", "/webjars/**", "/swagger-resources/configuration/ui", "/swagge‌​r-ui.html", "/swagger-resources/configuration/security").permitAll() – nikolai.serdiuk Mar 02 '17 at 18:43
  • 6
    Needed more rules: .antMatchers("/", "/csrf", "/v2/api-docs", "/swagger-resources/configuration/ui", "/configuration/ui", "/swagger-resources", "/swagger-resources/configuration/security", "/configuration/security", "/swagger-ui.html", "/webjars/**").permitAll() – Mate Šimović Jul 10 '18 at 11:37
  • 6
    Thanks for the answer! Is there any security risk allowing access to webjars/** ? – ssimm Nov 16 '18 at 14:54
  • very helpful answer – Praveenkumar Beedanal Sep 01 '20 at 15:02
  • 9
    I had to add `.., "/swagger-ui/**"...` to that list – FourtyTwo Jan 17 '21 at 14:14
  • 1
    @FourtyTwo me too, that's because Springfox 3.0.0 was changed the path. – Fabio Cardoso Jan 24 '21 at 15:33
  • This list absolutely didn't work for me. – Joey Nov 10 '21 at 23:59
  • 2
    Could you please add a description of the individual endpoints, why they need to be permitted? I have permitted only `/webjars/swagger-ui/**`, `swagger-ui.html` and `/v3/api-docs/**` and everything seems to be working so far, but perhaps there's some swagger functionality that I overlooked? Or are the `configuration` endpoints only for springfox? – Ondra K. Jan 12 '22 at 14:52
  • If you have actuator enable mappings locally and look at the `/actuator/mappings` response to make sure you have covered them all – 8bitme May 09 '23 at 11:00
85

I had the same problem using Spring Boot 2.0.0.M7 + Spring Security + Springfox 2.8.0. And I solved the problem using the following security configuration that allows public access to Swagger UI resources.

Answer updated in January 2021 : support Springfox 3

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    private static final String[] AUTH_WHITELIST = {
            // -- Swagger UI v2
            "/v2/api-docs",
            "/swagger-resources",
            "/swagger-resources/**",
            "/configuration/ui",
            "/configuration/security",
            "/swagger-ui.html",
            "/webjars/**",
            // -- Swagger UI v3 (OpenAPI)
            "/v3/api-docs/**",
            "/swagger-ui/**"
            // other public endpoints of your API may be appended to this array
    };


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.
                // ... here goes your custom security configuration
                authorizeRequests().
                antMatchers(AUTH_WHITELIST).permitAll().  // whitelist Swagger UI resources
                // ... here goes your custom security configuration
                antMatchers("/**").authenticated();  // require authentication for any endpoint that's not whitelisted
    }

}
naXa stands with Ukraine
  • 35,493
  • 19
  • 190
  • 259
  • 3
    after adding this class, I'm able to see swagger-ui but APIs are not accessed via postman even with access_token, getting access forbidden error as below, `{ "timestamp": 1519798917075, "status": 403, "error": "Forbidden", "message": "Access Denied", "path": "//shop" }` – Chandrakant Audhutwar Feb 28 '18 at 06:19
  • 1
    @ChandrakantAudhutwar delete `antMatchers("/**").authenticated()` statement or replace with your own authentication configuration. Be careful, you better know what you're doing with security. – naXa stands with Ukraine Feb 28 '18 at 06:30
  • 1
    yes, it worked. I was thinking of only bypassing swagger-ui, but other APIs as it is secured. now my APIs are also bypassed. – Chandrakant Audhutwar Feb 28 '18 at 09:39
  • @ChandrakantAudhutwar you do not need to copy-paste the whole `SecurityConfiguration` class to your project. You should have your own `SecurityConfiguration` where you permit requests to Swagger UI resources and keep your APIs secure. – naXa stands with Ukraine Feb 28 '18 at 09:58
  • I have `AuthorizationServerConfigurerAdapter` implemented class which makes API' authentication. – Chandrakant Audhutwar Feb 28 '18 at 10:01
  • @ChandrakantAudhutwar care to explain how you got around your issue? I can access my swagger page as well but when i hit "Try it" the response body is the login page so it's being redirected – GSUgambit Mar 07 '18 at 06:44
  • @ChandrakantAudhutwar it's as if I need to find a way to give swagger a security role so it's not anonymous i see this in my logs: o.s.s.access.vote.AffirmativeBased : Voter: org.springframework.security.web.access.expression.WebExpressionVoter@1afeff6, returned: -1 o.s.s.w.a.ExceptionTranslationFilter : Access is denied (user is anonymous); redirecting to authentication entry point – GSUgambit Mar 07 '18 at 06:46
  • 2
    I know this answer is old, but if you add "/swagger-ui/**" to the list, it will be perfect. Springfox 3.0.0 URL is that way. – Fabio Cardoso Jan 24 '21 at 15:32
33

I updated with /configuration/** and /swagger-resources/** and it worked for me.

@Override
public void configure(WebSecurity web) throws Exception {
    web.ignoring().antMatchers("/v2/api-docs", "/configuration/ui", "/swagger-resources/**", "/configuration/**", "/swagger-ui.html", "/webjars/**");

}
Akshata Suvarna
  • 331
  • 3
  • 2
32

For those who using a newer swagger 3 version org.springdoc:springdoc-openapi-ui

@Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/v3/api-docs/**", "/swagger-ui.html", "/swagger-ui/**");
    }
}
Dennis Gloss
  • 2,307
  • 4
  • 21
  • 27
  • 5
    Note: If this stops you from getting a "Authentication Required" error, but just shows you a blank page, I also had to add "/swagger-resources/**" and "/swagger-resources" in that list and it fixed it for me. – Vinícius M Jun 24 '20 at 14:16
  • for me ```.authorizeRequests().antMatchers("/v2/api-docs", "/swagger-resources/**", "/swagger-ui/**").permitAll().and()``` was sufficient – SPS Jan 14 '22 at 10:53
  • 1
    Thanks for posting this; just helped me with Swagger v3. – Aaron Feb 15 '22 at 20:07
6

if your springfox version higher than 2.5, should be add WebSecurityConfiguration as below:

@Override
public void configure(HttpSecurity http) throws Exception {
    // TODO Auto-generated method stub
    http.authorizeRequests()
        .antMatchers("/v2/api-docs", "/swagger-resources/configuration/ui", "/swagger-resources", "/swagger-resources/configuration/security", "/swagger-ui.html", "/webjars/**").permitAll()
        .and()
        .authorizeRequests()
        .anyRequest()
        .authenticated()
        .and()
        .csrf().disable();
}
duliu1990
  • 359
  • 4
  • 6
  • duliu1990 is right, since springfox 2.5+, all the springfox resources (swagger included) have moved under `/swagger-resources`. `/v2/api-docs` is the default swagger api endpoint (of no concern with the UI), which can be overridden with the config variable `springfox.documentation.swagger.v2.path` [springfox](http://springfox.github.io/springfox/docs/current/#springfox-swagger-ui) – Mahieddine M. Ichir Aug 23 '18 at 08:12
6

Some security config and you are ready with swagger open to all

For Swagger V2

@Configuration
@EnableWebSecurity
public class CabSecurityConfig extends WebSecurityConfigurerAdapter {


    private static final String[] AUTH_WHITELIST = {
            // -- swagger ui
            "/v2/api-docs", 
            "/swagger-resources/**", 
            "/configuration/ui",
            "/configuration/security", 
            "/swagger-ui.html",
            "/webjars/**"
    };

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        // ... here goes your custom security configuration
        http.authorizeRequests().
        antMatchers(AUTH_WHITELIST).permitAll(). // whitelist URL permitted
        antMatchers("/**").authenticated(); // others need auth
    }

}

For Swagger V3

@Configuration
@EnableWebSecurity
public class CabSecurityConfig extends WebSecurityConfigurerAdapter {


    private static final String[] AUTH_WHITELIST = {
            // -- swagger ui
            "/v2/api-docs",
            "/v3/api-docs",  
            "/swagger-resources/**", 
            "/swagger-ui/**",
             };

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        // ... here goes your custom security configuration
        http.authorizeRequests().
        antMatchers(AUTH_WHITELIST).permitAll(). // whitelist URL permitted
        antMatchers("/**").authenticated(); // others need auth
    }

}
Rupesh Kumar
  • 181
  • 2
  • 5
  • I've tested on v3 and can say this configuration works, but if into requests you need Principal, for example to extract username, then Swagger anyway fails, so I avoid spring boot open api. – Armer B. Apr 14 '22 at 21:30
5

More or less this page has answers but all are not at one place. I was dealing with the same issue and spent quite a good time on it. Now i have a better understanding and i would like to share it here:

I Enabling Swagger ui with Spring websecurity:

If you have enabled Spring Websecurity by default it will block all the requests to your application and returns 401. However for the swagger ui to load in the browser swagger-ui.html makes several calls to collect data. The best way to debug is open swagger-ui.html in a browser(like google chrome) and use developer options('F12' key ). You can see several calls made when the page loads and if the swagger-ui is not loading completely probably some of them are failing.

you may need to tell Spring websecurity to ignore authentication for several swagger path patterns. I am using swagger-ui 2.9.2 and in my case below are the patterns that i had to ignore:

However if you are using a different version your's might change. you may have to figure out yours with developer option in your browser as i said before.

@Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
public void configure(WebSecurity web) throws Exception {
    web.ignoring().antMatchers("/v2/api-docs", "/configuration/ui", 
            "/swagger-resources/**", "/configuration/**", "/swagger-ui.html"
            , "/webjars/**", "/csrf", "/");
}
}

II Enabling swagger ui with interceptor

Generally you may not want to intercept requests that are made by swagger-ui.html. To exclude several patterns of swagger below is the code:

Most of the cases pattern for web security and interceptor will be same.

@Configuration
@EnableWebMvc
public class RetrieveCiamInterceptorConfiguration implements WebMvcConfigurer {

@Autowired
RetrieveInterceptor validationInterceptor;

@Override
public void addInterceptors(InterceptorRegistry registry) {

    registry.addInterceptor(validationInterceptor).addPathPatterns("/**")
    .excludePathPatterns("/v2/api-docs", "/configuration/ui", 
            "/swagger-resources/**", "/configuration/**", "/swagger-ui.html"
            , "/webjars/**", "/csrf", "/");
}

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

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

}

Since you may have to enable @EnableWebMvc to add interceptors you may also have to add resource handlers to swagger similar to i have done in the above code snippet.

chanderdevx
  • 151
  • 2
  • 8
3

Limiting only to Swagger related resources:

.antMatchers("/v2/api-docs", "/swagger-resources/**", "/swagger-ui.html", "/webjars/springfox-swagger-ui/**");
m52509791
  • 449
  • 5
  • 13
  • for me ```.authorizeRequests().antMatchers("/v2/api-docs", "/swagger-resources/**", "/swagger-ui/**").permitAll().and()``` was sufficient – SPS Jan 14 '22 at 10:54
3

Here's a complete solution for Swagger with Spring Security. We probably want to only enable Swagger in our development and QA environment and disable it in the production environment. So, I am using a property (prop.swagger.enabled) as a flag to bypass spring security authentication for swagger-ui only in development/qa environment.

@Configuration
@EnableSwagger2
public class SwaggerConfiguration extends WebSecurityConfigurerAdapter implements WebMvcConfigurer {

@Value("${prop.swagger.enabled:false}")
private boolean enableSwagger;

@Bean
public Docket SwaggerConfig() {
    return new Docket(DocumentationType.SWAGGER_2)
            .enable(enableSwagger)
            .select()
            .apis(RequestHandlerSelectors.basePackage("com.your.controller"))
            .paths(PathSelectors.any())
            .build();
}

@Override
public void configure(WebSecurity web) throws Exception {
    if (enableSwagger)  
        web.ignoring().antMatchers("/v2/api-docs",
                               "/configuration/ui",
                               "/swagger-resources/**",
                               "/configuration/security",
                               "/swagger-ui.html",
                               "/webjars/**");
}

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    if (enableSwagger) {
        registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
    }
  }
}
Abdul Rahman
  • 1,833
  • 1
  • 21
  • 21
3

If you use Spring Boot 3, you need to use: springdoc-openapi-starter-webmvc-ui as it is writen in the doc introduction.

And use security configuration, something like this:

@Configuration
@EnableWebSecurity
@EnableMethodSecurity(securedEnabled = true, prePostEnabled = true, jsr250Enabled = true)
@RequiredArgsConstructor
public class SecurityConfiguration {

   @Bean
   public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
       return http
               .csrf().disable()
               .authorizeHttpRequests(a -> a
                       .requestMatchers("/v3/**", "/swagger-ui/**").permitAll()
                       .anyRequest().authenticated()
               ).build();
   }
}
  • Swagger UI: http://{your host}:{your port}/swagger-ui/index.html
  • JSON: http://{your host}:{your port}/v3/api-docs
  • yaml: http://{your host}:{your port}/v3/api-docs.yaml
Greg
  • 163
  • 1
  • 2
  • 9
  • I want to add authentication to my swagger. what can I do? So that no one can't see my API list without credentials. – Anjan Biswas Jul 21 '23 at 18:02
2

For Spring Security without the WebSecurityConfigurerAdapter it looks like (springdoc-openapi):

@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
    return web -> web.ignoring().requestMatchers("/v3/api-docs/**", "/swagger-ui.html", "/swagger-ui/**");
}

See Configuring WebSecurity

Grigory Kislin
  • 16,647
  • 10
  • 125
  • 197
1

Considering all of your API requests located with a url pattern of /api/.. you can tell spring to secure only this url pattern by using below configuration. Which means that you are telling spring what to secure instead of what to ignore.

@Override
protected void configure(HttpSecurity http) throws Exception {
  http
    .csrf().disable()
     .authorizeRequests()
      .antMatchers("/api/**").authenticated()
      .anyRequest().permitAll()
      .and()
    .httpBasic().and()
    .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
matt
  • 10,892
  • 3
  • 22
  • 34
Siddu
  • 23
  • 3
  • 1
    Thank you for this code snippet, which might provide some limited short-term help. A proper explanation [would greatly improve](//meta.stackexchange.com/q/114762) its long-term value by showing *why* this is a good solution to the problem, and would make it more useful to future readers with other, similar questions. Please [edit] your answer to add some explanation, including the assumptions you've made. – Toby Speight Mar 07 '18 at 12:46
1

I am using Spring Boot 5. I have this controller that I want an unauthenticated user to invoke.

  //Builds a form to send to devices   
@RequestMapping(value = "/{id}/ViewFormit", method = RequestMethod.GET)
@ResponseBody
String doFormIT(@PathVariable String id) {
    try
    {
        //Get a list of forms applicable to the current user
        FormService parent = new FormService();

Here is what i did in the configuuration.

  @Override
   protected void configure(HttpSecurity http) throws Exception {
    http
            .authorizeRequests()
            .antMatchers(
                    "/registration**",
                    "/{^[\\\\d]$}/ViewFormit",

Hope this helps....

smac2020
  • 9,637
  • 4
  • 24
  • 38
1

Just for enabling Swagger with Spring boot 2.5.4 and Springfox Swagger2:3.0.0 the following changes were sufficient for me:- .authorizeRequests().antMatchers("/v2/api-docs", "/swagger-resources/**", "/swagger-ui/**").permitAll().and()

Thanks to everyone for their suggestions in this thread!

SPS
  • 183
  • 1
  • 2
  • 10
0

Add a Bean like this:

@Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
http.authorizeExchange()
    .pathMatchers(
        "/v2/api-docs",
        "/swagger-ui/**",
        "/swagger-resources/**",
        "/*/swagger-resources/**",
        "/*/v2/api-docs")
    .permitAll()
    .and()
    .authorizeExchange()
    .anyExchange()
    .permitAll();
http.httpBasic().disable();
http.csrf().disable();
return http.build();
}
Imranmadbar
  • 4,681
  • 3
  • 17
  • 30