Spring Security Basics

Spring Security provides authentication, authorization, and protection against common attacks (CSRF, XSS, etc.). This article explains core concepts, common configuration, and a reference table to get you started.

Overview

  • Authentication: Answers "who are you?" Common methods: form login, JWT, OAuth2, Basic Auth. UserDetailsService loads user data; PasswordEncoder validates passwords.
  • Authorization: Answers "what can you do?" Role-based (ROLE_ADMIN), permission-based (user:read), method-level @PreAuthorize, and URL rules.
  • Filter chain: Each request passes through a series of filters (e.g. UsernamePasswordAuthenticationFilter, FilterSecurityInterceptor). After auth succeeds, authorization decides whether to allow the request.
  • Session: Default is session-based; you can switch to stateless JWT where each request carries a token.

Example

Example 1: Basic security config

Java
@Configuration
@EnableWebSecurity
public class SecurityConfig {
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests(a -> a
            .requestMatchers("/public/**").permitAll()
            .requestMatchers("/admin/**").hasRole("ADMIN")
            .anyRequest().authenticated()
        ).formLogin();
        return http.build();
    }
}
  • permitAll(): no auth required. hasRole("ADMIN"): requires ROLE_ADMIN. authenticated(): any logged-in user.
  • Order matters: more specific rules first; anyRequest() should come last.

Example 2: Custom UserDetailsService

Java
@Service
public class MyUserDetailsService implements UserDetailsService {
    @Autowired
    private UserRepository userRepo;

    @Override
    public UserDetails loadUserByUsername(String username) {
        User user = userRepo.findByUsername(username)
            .orElseThrow(() -> new UsernameNotFoundException(username));
        return new org.springframework.security.core.userdetails.User(
            user.getUsername(),
            user.getEncodedPassword(),
            user.getAuthorities()
        );
    }
}
  • Spring Security uses UserDetails for the authenticated principal. Your service loads from DB and returns a User (or custom implementation) with username, password, and authorities.

Example 3: PasswordEncoder

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

// When saving a new user:
String encoded = passwordEncoder.encode(rawPassword);

// Validation is done by Spring; you only need to return the encoded password from UserDetails
  • Never store plain text passwords. BCrypt, Argon2, SCrypt are recommended. Spring compares the raw password from the login form with the encoded one from UserDetails.

Example 4: JWT flow

  • On login success, generate a JWT and return it (e.g. in response body or cookie).
  • Subsequent requests send Authorization: Bearer <token>.
  • A JwtAuthenticationFilter (or similar) parses the token, validates it, and sets SecurityContext.
  • No server-side session; the token carries identity and optionally roles.

Example 5: Core components

ComponentRole
UserDetailsServiceLoad user by username; return UserDetails
PasswordEncoderEncode and validate passwords
AuthenticationManagerEntry point for authentication
SecurityContextHolds current Authentication (ThreadLocal)
FilterSecurityInterceptorDecides if request is allowed (authorization)

Example 6: Method-level authorization

Java
@PreAuthorize("hasRole('ADMIN') or #id == authentication.principal.id")
public User getById(Long id) { }

@PreAuthorize("hasAuthority('user:read')")
public List<User> list() { }
  • @PreAuthorize uses SpEL; #id is the method parameter; authentication.principal is the current user.
  • Enable with @EnableMethodSecurity (or @EnableGlobalMethodSecurity(prePostEnabled = true) in older versions).

Example 7: CSRF

  • For stateful apps (form login, cookies), CSRF protection is on by default. Include the CSRF token in forms.
  • For stateless APIs (JWT in header), CSRF is usually disabled: http.csrf(csrf -> csrf.disable()).
  • CSRF attacks abuse the browser's automatic sending of cookies; with JWT in a header, the attacker cannot add it from another site.

Core Mechanism / Behavior

  • Filter chain: Filters run in order. UsernamePasswordAuthenticationFilter handles form login; FilterSecurityInterceptor enforces URL authorization. Custom filters can be added.
  • SecurityContext: Stored in ThreadLocal; cleared after the request. Holds the current Authentication (principal, credentials, authorities).
  • PasswordEncoder: One-way hash; verification compares hash of input with stored hash. Use adaptive algorithms (BCrypt, Argon2) that are slow by design.

Key Rules

  • Passwords: Always hash with PasswordEncoder; never store plain text.
  • CSRF: Stateful forms need CSRF token; for pure API + JWT you can disable it.
  • Least privilege: Default deny; explicitly permit what is needed. Be careful with permitAll in production.
  • Sensitive endpoints: Protect admin and internal APIs; avoid exposing them without auth.

What's Next

See API Gateway for centralized auth. See OAuth2 and JWT for auth protocols.