Spring Security (Authentication & Authorization)
Secure Spring apps. Learn security filter chains, custom user details, JWT authentications, OAuth2, and password encoding.
Downloaded from PrepIQ (https://prepiq.online)
Q1. What is Spring Security and how does the filter chain work?
Spring Security is a framework that provides authentication, authorization, and protection against common attacks (CSRF, session fixation, clickjacking) for Spring applications. It works by inserting a chain of servlet filters, FilterChainProxy, in front of the application, with each filter handling one concern — e.g. UsernamePasswordAuthenticationFilter for form login, BasicAuthenticationFilter for HTTP Basic, or a custom JWT filter.
Every incoming request passes through this chain before reaching the controller; a filter can authenticate the request, populate the SecurityContext, or reject the request outright, so by the time a request reaches a controller, Spring Security has already determined who the caller is and what they're allowed to do.
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(auth -> auth
.requestMatchers("/public/**").permitAll()
.anyRequest().authenticated());
return http.build();
}
}
Q2. What is the difference between authentication and authorization in Spring Security?
Authentication answers "who are you?" — verifying a user's identity through credentials such as a username/password, JWT token, or OAuth2 token, resulting in a populated Authentication object stored in the SecurityContext. Authorization answers "what are you allowed to do?" — deciding whether the authenticated user has permission to access a resource or perform an action, based on roles or authorities.
In Spring Security, authentication happens first (via an AuthenticationManager and AuthenticationProvider), and authorization happens afterward, evaluated through URL-based rules in the filter chain or method-level annotations like @PreAuthorize.
http.authorizeHttpRequests(auth -> auth
.requestMatchers("/admin/**").hasRole("ADMIN")
.requestMatchers("/user/**").hasAnyRole("USER", "ADMIN")
.anyRequest().authenticated());
Q3. How do you implement JWT authentication in Spring Boot?
JWT (JSON Web Token) authentication is stateless: after a user logs in with credentials, the server generates a signed token containing claims (user id, roles, expiry) and returns it to the client, which sends it in the Authorization: Bearer <token> header on every subsequent request.
A custom OncePerRequestFilter is added to the filter chain to extract and validate the token on each request, parse its claims, and populate the SecurityContext if valid, without needing a server-side session — making JWT well suited for stateless REST APIs and microservices.
public class JwtAuthFilter extends OncePerRequestFilter {
protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain) {
String token = extractToken(req);
if (token != null && jwtUtil.validateToken(token)) {
UsernamePasswordAuthenticationToken auth = jwtUtil.getAuthentication(token);
SecurityContextHolder.getContext().setAuthentication(auth);
}
chain.doFilter(req, res);
}
}
Q4. How does OAuth2 login work in Spring Boot (Spring Security OAuth2 Client)?
Spring Security's OAuth2 Client support lets an application delegate authentication to an external identity provider (Google, GitHub, Okta) using the OAuth2 Authorization Code flow. Adding spring-boot-starter-oauth2-client and configuring the provider's client ID, secret, and endpoints auto-configures the redirect, token exchange, and user-info retrieval.
After a successful login, Spring Security populates an OAuth2AuthenticationToken containing the user's attributes from the provider, and applications can map these attributes to internal roles through a custom OAuth2UserService. This is distinct from acting as an OAuth2 Resource Server, which instead validates incoming bearer tokens issued by an authorization server.
spring.security.oauth2.client.registration.google.client-id=YOUR_CLIENT_ID
spring.security.oauth2.client.registration.google.client-secret=YOUR_SECRET
spring.security.oauth2.client.registration.google.scope=email,profile
Q5. How does password encoding work in Spring Security (BCryptPasswordEncoder)?
Spring Security never stores or compares plain-text passwords. A PasswordEncoder bean, typically BCryptPasswordEncoder, hashes the password with a random salt and a configurable work factor (strength) before it is persisted, and the same encoder's matches() method is used to compare a raw login password against the stored hash.
BCrypt is preferred over faster hashes like MD5 or SHA because it's intentionally slow and its work factor can be increased over time as hardware gets faster, making brute-force and rainbow-table attacks impractical even if the password database is leaked.
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(12); // strength factor
}
String hashed = passwordEncoder.encode(rawPassword);
boolean matches = passwordEncoder.matches(rawPassword, hashed);
Q6. How do you implement method-level security with @PreAuthorize and @PostAuthorize?
Method-level security lets you enforce authorization rules directly on service or controller methods instead of only at the URL level, enabled with @EnableMethodSecurity. @PreAuthorize evaluates a SpEL expression before the method executes and blocks the call if it evaluates to false, commonly checking roles or matching the authenticated user against a method argument.
@PostAuthorize evaluates after the method executes, allowing checks against the returned object (e.g. ensuring a fetched document belongs to the requesting user), and @PreFilter/@PostFilter can filter collection arguments or return values based on a condition per element.
@PreAuthorize("hasRole('ADMIN') or #userId == authentication.principal.id")
public User getUser(Long userId) { ... }
@PostAuthorize("returnObject.owner == authentication.name")
public Document getDocument(Long id) { ... }
Q7. What is CSRF protection and when should it be disabled in Spring Boot?
CSRF (Cross-Site Request Forgery) protection prevents a malicious site from tricking an authenticated user's browser into submitting an unwanted state-changing request using the user's existing session cookie. Spring Security defends against this by requiring a unique, unpredictable CSRF token to be included in state-changing requests (POST, PUT, DELETE), which it validates against the token stored in the user's session.
CSRF protection matters for browser-based, cookie-authenticated session apps but is typically disabled for stateless REST APIs authenticated with a bearer token (JWT) or API key, since those aren't vulnerable to the cookie-based attack CSRF protection defends against, and enforcing it would break token-based clients that don't send the CSRF header.
http.csrf(csrf -> csrf.disable()); // typical for stateless JWT-secured REST APIs
Q8. How do you configure CORS in Spring Boot?
CORS (Cross-Origin Resource Sharing) is a browser security mechanism that blocks a web page from calling an API on a different origin unless the server explicitly allows it via response headers. In Spring Boot, CORS is configured either globally with a WebMvcConfigurer bean or per-controller with @CrossOrigin, specifying allowed origins, methods, and headers.
When Spring Security is also on the classpath, CORS must additionally be enabled inside the security filter chain with http.cors(Customizer.withDefaults()), referencing a CorsConfigurationSource bean — configuring CORS at the MVC layer alone is not enough once Security's filters are in front of the request.
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowedOrigins(List.of("https://example.com"));
config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return source;
}
Q9. What is the difference between a Custom UserDetailsService and using in-memory authentication?
In-memory authentication defines a fixed set of users, passwords, and roles directly in configuration using InMemoryUserDetailsManager, which is useful only for demos, prototypes, or tests since users can't be added or changed without redeploying the application.
A custom UserDetailsService implementation loads user data from a real source, typically a database via a repository, overriding loadUserByUsername() to return a UserDetails object built from the stored user's credentials and authorities. This is the standard approach for any real application, since it allows dynamic user management and integrates with the rest of the persistence layer.
@Service
public class CustomUserDetailsService implements UserDetailsService {
public UserDetails loadUserByUsername(String username) {
User user = userRepository.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("Not found"));
return new org.springframework.security.core.userdetails.User(
user.getUsername(), user.getPassword(), user.getAuthorities());
}
}
Q10. What is Spring Security's SecurityContext and how is it propagated?
The SecurityContext holds the current Authentication object, representing the currently authenticated user, their credentials, and granted authorities. It's stored in a SecurityContextHolder, which by default uses a ThreadLocal so the context is available anywhere within the same thread handling a request, without needing to pass the user explicitly through every method call.
Because it's thread-local by default, the context does not automatically propagate to new threads spawned for async processing (@Async, a new Thread, or a thread pool); propagating it requires either passing the Authentication explicitly or switching the holder strategy to MODE_INHERITABLETHREADLOCAL.
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String username = auth.getName();
Collection<? extends GrantedAuthority> roles = auth.getAuthorities();
Spring Security (Authentication & Authorization)
Secure Spring apps. Learn security filter chains, custom user details, JWT authentications, OAuth2, and password encoding.
What is Spring Security and how does the filter chain work?
Spring Security is a framework that provides authentication, authorization, and protection against common atta...
What is the difference between authentication and authorization in Spring Security?
Authentication answers "who are you?" — verifying a user's identity through credentials such as a username/pas...
How do you implement JWT authentication in Spring Boot?
JWT (JSON Web Token) authentication is stateless: after a user logs in with credentials, the server generates...
How does OAuth2 login work in Spring Boot (Spring Security OAuth2 Client)?
Spring Security's OAuth2 Client support lets an application delegate authentication to an external identity pr...
How does password encoding work in Spring Security (BCryptPasswordEncoder)?
Spring Security never stores or compares plain-text passwords. A PasswordEncoder bean, typically BCryptPasswor...
How do you implement method-level security with @PreAuthorize and @PostAuthorize?
Method-level security lets you enforce authorization rules directly on service or controller methods instead o...
What is CSRF protection and when should it be disabled in Spring Boot?
CSRF (Cross-Site Request Forgery) protection prevents a malicious site from tricking an authenticated user's b...
How do you configure CORS in Spring Boot?
CORS (Cross-Origin Resource Sharing) is a browser security mechanism that blocks a web page from calling an AP...
What is the difference between a Custom UserDetailsService and using in-memory authentication?
In-memory authentication defines a fixed set of users, passwords, and roles directly in configuration using In...
What is Spring Security's SecurityContext and how is it propagated?
The SecurityContext holds the current Authentication object, representing the currently authenticated user, th...