Home/Learn/Spring Boot/Spring Security Basics

Spring Security Basics

Intermediate
Security

Spring Security adds authentication and authorisation to your application; it plugs in as a chain of servlet filters that intercept every HTTP request.

Overview

Spring Security is the de-facto security framework for Spring Boot applications. It integrates as a chain of servlet filters (the SecurityFilterChain) that intercept every HTTP request before it reaches your controllers. The chain handles authentication (who are you?), authorisation (are you allowed?), CSRF protection, session management, and more — all configurable through a fluent Java DSL. Spring Boot auto-configures sensible defaults (form login, basic auth, a random in-memory password) so the application is protected out of the box. In production you replace the defaults by declaring a SecurityFilterChain @Bean and a UserDetailsService (or an AuthenticationProvider) that validates credentials against your data store.

SecurityFilterChain — The Core

Spring Security registers a DelegatingFilterProxy in the servlet container that delegates to a FilterChainProxy. The FilterChainProxy holds one or more SecurityFilterChain beans. Each chain has a request matcher and an ordered list of Security filters (CORS, CSRF, authentication, authorisation, session management, exception handling, etc.).

When a request arrives, the first matching chain processes it. If authentication fails, an AuthenticationEntryPoint sends a 401. If authorisation fails, an AccessDeniedHandler sends a 403.

Java — Spring Security Config
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            // Stateless REST API — disable session & CSRF
            .sessionManagement(s -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
            .csrf(csrf -> csrf.disable())

            // Authorisation rules
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/api/auth/**").permitAll()        // public endpoints
                .requestMatchers("/api/admin/**").hasRole("ADMIN")  // admin only
                .anyRequest().authenticated()                        // all others need auth
            )

            // Use JWT filter instead of form login
            .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class)

            // Return 401/403 as JSON, not redirect
            .exceptionHandling(ex -> ex
                .authenticationEntryPoint((req, res, e) -> {
                    res.setStatus(401);
                    res.getWriter().write("{"error":"Unauthorized"}");
                })
            );

        return http.build();
    }

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

UserDetailsService & Authentication

Spring Security uses UserDetailsService to load user details by username. The returned UserDetails object contains the username, encoded password, and a list of GrantedAuthority (roles/permissions). Spring compares the encoded submitted password against the stored hash using the configured PasswordEncoder.

For database-backed authentication, implement UserDetailsService and query your user repository. Always store passwords with BCrypt — never plain text or MD5.

Java — UserDetailsService
@Service
@RequiredArgsConstructor
public class AppUserDetailsService implements UserDetailsService {

    private final UserRepository userRepo;

    @Override
    public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
        User user = userRepo.findByEmail(email)
            .orElseThrow(() -> new UsernameNotFoundException("User not found: " + email));

        return org.springframework.security.core.userdetails.User.builder()
            .username(user.getEmail())
            .password(user.getPasswordHash())          // BCrypt hash stored in DB
            .roles(user.getRole().name())              // e.g. "USER", "ADMIN"
            .accountExpired(!user.isActive())
            .build();
    }
}

// Wire it into the AuthenticationManager
@Bean
public AuthenticationManager authManager(UserDetailsService uds,
                                         PasswordEncoder encoder) {
    DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
    provider.setUserDetailsService(uds);
    provider.setPasswordEncoder(encoder);
    return new ProviderManager(provider);
}

Method-Level Security with @PreAuthorize

@EnableMethodSecurity activates method-level security annotations. @PreAuthorize runs a Spring EL expression before the method; @PostAuthorize checks after. These let you enforce fine-grained rules at the service layer, independent of URL patterns — for example, ensuring a user can only access their own resources.

Java — Method Security
@Configuration
@EnableMethodSecurity   // activates @PreAuthorize, @PostAuthorize, @Secured
public class MethodSecurityConfig { }

@Service
public class OrderService {

    // Only admins or the order owner can access this
    @PreAuthorize("hasRole('ADMIN') or #userId == authentication.principal.id")
    public List<Order> getOrdersByUser(Long userId) {
        return orderRepo.findByUserId(userId);
    }

    @PreAuthorize("hasRole('ADMIN')")
    public void deleteOrder(Long orderId) {
        orderRepo.deleteById(orderId);
    }
}

// Access authentication in a controller
@GetMapping("/me")
public UserProfile getProfile(Authentication auth) {
    AppUserDetails principal = (AppUserDetails) auth.getPrincipal();
    return userService.getProfile(principal.getId());
}

Key Points to Remember

  • 1Spring Security works as a chain of servlet filters (SecurityFilterChain) that process every request before it reaches controllers.
  • 2Disable CSRF and sessions for stateless REST APIs; enable them for server-rendered apps with form login.
  • 3Always use BCryptPasswordEncoder — never store plain-text or MD5-hashed passwords.
  • 4UserDetailsService.loadUserByUsername() is the extension point for loading users from your database.
  • 5@PreAuthorize("hasRole('ADMIN')") enforces access control at the method/service level via Spring EL expressions.
  • 6Return 401/403 as JSON (not HTML redirects) for REST APIs by customising the AuthenticationEntryPoint and AccessDeniedHandler.

Interview Questions

Sign in to ask Aria
1

How does Spring Security work internally — what is a SecurityFilterChain?

MediumAmazon
2

How do you secure specific endpoints in Spring Boot — allow some public, some authenticated, some admin only?

MediumFlipkart
3

What is UserDetailsService and how does Spring Security use it?

MediumInfosys
4

What is the difference between @PreAuthorize and URL-based security rules?

MediumThoughtworks
5

Why should you always use BCrypt for password storage? What is wrong with MD5 or SHA-1?

EasyGoogle

Ask Aria about Spring Security Basics

Your personal AI tutor — ask anything about this concept

Revision Status

Personal Notes

Sign in to save personal notes for this topic.

Discussion

Sign in to join the discussion.

Loading discussion…