Spring Security Fundamentals
Before JWT, before roles — every secured request in Spring passes through the same mechanism. This module is that mechanism.
Learning objectives
- Beginner: State the difference between authentication and authorization in one sentence each.
- Intermediate: Trace a request through the security filter chain and identify where authentication actually happens.
- Advanced: Configure a custom SecurityFilterChain bean that intentionally loosens or tightens Spring Security's secure-by-default posture for a specific use case.
| Term | Question it answers |
|---|---|
| Authentication | "Who are you?" — verifying identity, e.g. via a valid JWT (Module 13). |
| Authorization | "What are you allowed to do?" — verifying permission for a specific action, e.g. via roles (Module 14). |
A request can be authenticated (the server knows exactly who you are) and still be unauthorized for a specific action (you're not allowed to delete this resource) — the two checks are related but genuinely separate, and Spring Security models them as separate concerns throughout.
◆ The problem
Security checks (is this request authenticated? does it have the right role?) need to happen before a request reaches your @RestController — putting that logic inside every controller method would be repetitive and trivially easy to forget on a new endpoint.
Spring Security intercepts every request via a chain of servlet filters, positioned in front of the DispatcherServlet from Module 06 §2 — by the time a request reaches your controller, security has already run.
Every request runs through the security filter chain before it ever reaches the DispatcherServlet — by the time your controller method runs, authentication and authorization have already been decided.
@Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { return http .csrf(csrf -> csrf.disable()) // stateless JWT APIs don't need CSRF protection — see internals box .sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .authorizeHttpRequests(auth -> auth .requestMatchers("/auth/**").permitAll() .requestMatchers("/admin/**").hasRole("ADMIN") .anyRequest().authenticated()) .build(); } }
◆ Under the hood — why CSRF is disabled for a JWT API
CSRF protection defends against an attack that exploits browser-managed session cookies being sent automatically with every request to a site. A stateless JWT API (Module 13) doesn't use cookie-based sessions — the token is sent explicitly in an Authorization header by client code, which a malicious cross-site request can't forge the way it can a cookie. CSRF disabling is correct specifically because of statelessness, not a generic security shortcut — a cookie-based session API would need it enabled.
💻 Code example
@Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { return http .csrf(csrf -> csrf.disable()) // stateless JWT APIs don't need CSRF protection — see internals box .sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .authorizeHttpRequests(auth -> auth .requestMatchers("/auth/**").permitAll() .requestMatchers("/admin/**").hasRole("ADMIN") .anyRequest().authenticated()) .build(); } }
@Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); // includes a per-password random salt automatically }
// registering a user user.setPassword(passwordEncoder.encode(rawPassword)); // store only the hash
// verifying a login attempt boolean matches = passwordEncoder.matches(rawPasswordFromLogin, user.getPassword());
▲ Pitfall
Never store or compare plain-text passwords, and never use a fast general-purpose hash like plain SHA-256 for passwords — BCrypt is deliberately slow and includes automatic per-password salting specifically to resist brute-force and rainbow-table attacks, properties a generic hash function doesn't provide.
✓ Quick recap
What's the practical difference between authentication and authorization? Authentication verifies who you are; authorization verifies what you're allowed to do — a request can be authenticated but still unauthorized for a specific action. Why is it correct to disable CSRF protection for a stateless JWT API? CSRF defends against cookie-based session forgery; a stateless API sends its token explicitly in a header, which cross-site requests can't forge the way they can an automatically-sent cookie.
💻 Code example
@Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); // includes a per-password random salt automatically }
Want a visual for this concept?
Generate a diagram tailored to “Spring Security Fundamentals” — the AI picks whichever visual (flowchart, comparison, sequence, etc.) best fits.
Sign in to generate a visual →