Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/spring-projects/spring-boot/llms.txt

Use this file to discover all available pages before exploring further.

When spring-boot-starter-security is on the classpath, Spring Boot auto-configures form-based login and HTTP Basic authentication for all endpoints. The auto-configuration is designed to back off completely when you define your own security beans, giving you full control without fighting the defaults. This guide covers the most common security customizations step by step.

Understand the default security configuration

Out of the box, Spring Boot provides:
  • A single in-memory user with username user and a randomly generated password printed at WARN level on startup.
  • Form-based login or HTTP Basic auth for all requests (selected by content negotiation on the Accept header).
  • A DefaultAuthenticationEventPublisher for publishing authentication events.
The generated password looks like this at startup:
Using generated security password: 78fa095d-3f4c-48b1-ad50-e24c31d5cf35

This generated password is for development use only. Your security configuration must be updated before running your application in production.
To set a fixed username and password for development:
spring:
  security:
    user:
      name: admin
      password: secret

Switch to a custom UserDetailsService

To replace the auto-configured in-memory UserDetailsService with your own, define a bean of type UserDetailsService:
@Bean
public UserDetailsService userDetailsService(UserRepository userRepository) {
    return username -> userRepository.findByUsername(username)
        .map(user -> User.withUsername(user.getUsername())
            .password(user.getPasswordHash())
            .roles(user.getRoles().toArray(new String[0]))
            .build())
        .orElseThrow(() -> new UsernameNotFoundException("User not found: " + username));
}
As soon as Spring Boot detects a UserDetailsService, AuthenticationProvider, or AuthenticationManager bean, it backs off the auto-configured InMemoryUserDetailsManager.
Always store passwords hashed with a strong encoder. Inject a PasswordEncoder bean (e.g., BCryptPasswordEncoder) and use it both when storing passwords and when configuring the DaoAuthenticationProvider.

Use in-memory users for development

For local development and testing, define an InMemoryUserDetailsManager bean explicitly:
@Bean
public UserDetailsService inMemoryUserDetailsService() {
    UserDetails user = User.withDefaultPasswordEncoder()
        .username("user")
        .password("password")
        .roles("USER")
        .build();

    UserDetails admin = User.withDefaultPasswordEncoder()
        .username("admin")
        .password("admin")
        .roles("USER", "ADMIN")
        .build();

    return new InMemoryUserDetailsManager(user, admin);
}
User.withDefaultPasswordEncoder() is not suitable for production use. It is a convenience method for prototyping only. Use a BCryptPasswordEncoder and properly hashed passwords in any environment that handles real user data.

Override Spring Security auto-configuration

To completely replace the default web security settings, define a SecurityFilterChain bean:
@Configuration
@EnableWebSecurity
public class MySecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                .anyRequest().authenticated())
            .formLogin(withDefaults())
            .httpBasic(withDefaults());
        return http.build();
    }
}
Defining this bean switches off Spring Boot’s SpringBootWebSecurityConfiguration while leaving UserDetailsServiceAutoConfiguration in place (unless you also define your own UserDetailsService).

Secure specific URL patterns

To apply different rules to different URL paths — for example, permit /public/** without authentication and require authentication for /api/**:
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
        .authorizeHttpRequests(auth -> auth
            .requestMatchers("/public/**").permitAll()
            .requestMatchers("/api/**").authenticated()
            .anyRequest().denyAll())
        .formLogin(withDefaults());
    return http.build();
}
Use requestMatchers with Ant patterns to match URL paths. Rules are evaluated in the order they are declared — place more specific patterns before broader ones.

Add HTTP Basic auth alongside form login

To accept both browser-based form logins and programmatic HTTP Basic authentication:
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
        .authorizeHttpRequests(auth -> auth
            .anyRequest().authenticated())
        .formLogin(form -> form
            .loginPage("/login")
            .permitAll())
        .httpBasic(withDefaults());
    return http.build();
}
Spring Security’s content negotiation strategy selects the appropriate challenge based on the Accept header: browsers receive the login form redirect, and API clients receive a 401 with a WWW-Authenticate: Basic header.

Disable CSRF protection for REST APIs

CSRF protection is enabled by default and is important for browser-based applications. For stateless REST APIs that authenticate via tokens rather than cookies, disable it:
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
        .csrf(csrf -> csrf.disable())
        .authorizeHttpRequests(auth -> auth
            .anyRequest().authenticated())
        .httpBasic(withDefaults());
    return http.build();
}
Only disable CSRF when your API is genuinely stateless and does not use session cookies for authentication. If your application serves both a browser UI and a REST API, apply CSRF selectively using ignoringRequestMatchers rather than disabling it globally.

Configure CORS

To define cross-origin resource sharing rules, add a CorsConfigurationSource bean and enable CORS in the security filter chain:
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
        .cors(cors -> cors.configurationSource(corsConfigurationSource()))
        .authorizeHttpRequests(auth -> auth.anyRequest().authenticated());
    return http.build();
}

@Bean
public CorsConfigurationSource corsConfigurationSource() {
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowedOrigins(List.of("https://example.com"));
    config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE"));
    config.setAllowedHeaders(List.of("*"));
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", config);
    return source;
}
CORS configuration in the SecurityFilterChain takes precedence over @CrossOrigin annotations and MVC-level CORS mappings. Define it here when you need to apply it uniformly across all secured endpoints.

Configure OAuth2 login with GitHub or Google

To add social login, follow these steps:
1

Add the OAuth2 client dependency

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
2

Register your application with the provider

Register a new OAuth2 application on your chosen provider’s developer console:Set the redirect URI to http://localhost:8080/login/oauth2/code/{registrationId} (replace localhost:8080 with your actual host and {registrationId} with github or google).
3

Add credentials to application.yaml

spring:
  security:
    oauth2:
      client:
        registration:
          github:
            client-id: your-github-client-id
            client-secret: your-github-client-secret
          google:
            client-id: your-google-client-id
            client-secret: your-google-client-secret
Spring Boot pre-configures provider details for github and google — you only need the client ID and secret.
4

Configure the security filter chain

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
        .authorizeHttpRequests(auth -> auth
            .requestMatchers("/").permitAll()
            .anyRequest().authenticated())
        .oauth2Login(withDefaults());
    return http.build();
}
Spring Boot handles the OAuth2 authorization code flow, token exchange, and user info retrieval automatically.
Store your client ID and secret in environment variables or a secrets manager rather than committing them to application.yaml. Use Spring Boot’s externalized configuration support — for example, ${GITHUB_CLIENT_ID} — to inject them at runtime.

Enable HTTPS when behind a proxy

If your application runs behind a reverse proxy that terminates SSL, configure Tomcat to trust the forwarded headers:
server:
  tomcat:
    remoteip:
      remote-ip-header: "x-forwarded-for"
      protocol-header: "x-forwarded-proto"
The presence of either property activates Tomcat’s RemoteIpValve, which causes HttpServletRequest.isSecure() to return true when the x-forwarded-proto: https header is present. This allows Spring Security’s requiresSecure() checks to work correctly downstream of the proxy.

Build docs developers (and LLMs) love