Skip to main content

Command Palette

Search for a command to run...

Spring Security Explained : A Complete Guide for Java Developers

Learn how to secure your Spring Boot applications from scratch - from basic HTTP auth to database based user

Updated
4 min read
Spring Security Explained : A Complete Guide for Java Developers

What is Spring Security?

Spring Security is a highly customizable and powerful authentication and access-control framework for Java applications. It is standard for securing Spring-based applications and handles both authentication and authorization.

Spring Security provides protection against multiple common attacks like CSRF, clickjacking, and more.

Spring Security supports both annotation-based and Java-based configuration for customizing security rules.

Authentication and Authorization

  • Authentication: Verifies the identity of users (e.g., login with username and password).

  • Authorization: Determines whether a user has permission to perform a specific action (e.g., access a page or API).

Password Management

  • Supports modern password encoding mechanisms such as bcrypt.

  • Provides built-in utilities for hashing and verifying passwords.

How Spring Security Works

Spring Security uses chain of filters that intercepts every HTTP request.

SecurityFilterChain is the main which decides which requests require authentication, what type of login to use, and how sessions are handled.

Add Spring Security Dependency

To get started, add the Spring Security starter to your pom.xml

<!-- Spring Security -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

Note: After adding Spring Security, all endpoints are secured by default, and a random password is printed in the console at startup. The username is user

Basic HTTP Authentication

Let's create a basic security configuration.

In Spring Boot 3.x, we use the new component-based approach instead of extending WebSecurityConfigurerAdapter.



@Configuration
@EnableWebSecurity
public class SecurityConfig {

  @Bean
  public SecurityFilterChain securityFilterChain(HttpSecurity http)
  throws Exception {

    http
      .csrf(csrf -> csrf.disable())
      .authorizeHttpRequests(auth -> auth
        .requestMatchers("/api/public/**").permitAll()
        .requestMatchers("/api/admin/**").hasRole("ADMIN")
        .requestMatchers("/api/user/**").hasRole("USER")
        .anyRequest().authenticated()
      )
      .httpBasic(Customizer.withDefaults());

    return http.build();
  }
}

For REST APIs, always disable CSRF protection, while for web applications, you should keep CSRF protection enabled.

Custom UserDetailsService

Instead of using the default in-memory user, we load users from a database by implementing UserDetailsService.

User Entity

@Entity
@Table(name = "users")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(unique = true)
    private String username;

    private String password;

    private String role; // e.g. ADMIN, USER

    // getters and setters...
}

Custom UserDetailsService Implementation

@Service
public class CustomUserDetailsService
        implements UserDetailsService {

    @Autowired
    private UserRepository userRepository;

    @Override
    public UserDetails loadUserByUsername(String username)
            throws UsernameNotFoundException {

        User user = userRepository.findByUsername(username)
            .orElseThrow(() -> new UsernameNotFoundException(
                "User not found: " + username));

        return org.springframework.security.core.userdetails.User
            .withUsername(user.getUsername())
            .password(user.getPassword())
            .roles(user.getRole())
            .build();
    }
}

Password Encoding with BCrypt

Spring Security integrates BCryptPasswordEncoder out of the box so never store plain text passwords.

@Bean
public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}

// Used When Registering a New user
public void registerUser(String username, String rawPassword) {
    User user = new User();
    user.setUsername(username);
    user.setPassword(passwordEncoder.encode(rawPassword)); //BCryptPasswordEncoder
    user.setRole("USER");
    userRepository.save(user);
}

BCrypt automatically handles salting and is designed to be slow, making brute-force attacks computationally expensive.

Role-Based Authorization

We can restrict access to specific endpoints based on roles using both annotations and configuration.

Via Annotations (Method Level Security)

First, we need to enable method security in config

@Configuration
@EnableMethodSecurity  // need to enable this
public class SecurityConfig { ... }

Then we can use annotations directly on controller methods

@RestController
@RequestMapping("/api")
public class controller {

    @GetMapping("/dashboard")
    @PreAuthorize("hasRole('ADMIN')")
    public ResponseEntity<String> getDashboard() {
        return ResponseEntity.ok("Admin Dashboard");
    }

    @DeleteMapping("/users/{id}")
    @PreAuthorize("hasRole('ADMIN')")
    public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
        userService.deleteUser(id);
        return ResponseEntity.noContent().build();
    }
}

Via Security Config

@Configuration
@EnableWebSecurity
public class SecurityConfig {

  @Bean
  public SecurityFilterChain securityFilterChain(HttpSecurity http)
  throws Exception {

    http
      .csrf(csrf -> csrf.disable())
      .authorizeHttpRequests(auth -> auth
        .requestMatchers("/api/public/**").permitAll()
        .requestMatchers("/api/admin/**").hasRole("ADMIN")
        .requestMatchers("/api/user/**").hasRole("USER", "ADMIN")
        .anyRequest().authenticated()
      )
      .httpBasic(Customizer.withDefaults());

    return http.build();
  }
}

Summary

We have now learned how to secure your Spring Boot applications from scratch - from basic HTTP auth to database based user

  • Added Spring Security dependency

  • Created a custom SecurityFilterChain

  • Implemented UserDetailsService with database

  • Encoded passwords with BCrypt

  • Set up role-based authorization