Spring Security is the topic where a Spring Boot interview stops testing syntax and starts testing whether you understand how a request is actually secured. Almost every backend role touches authentication, and interviewers use it to separate people who added a dependency from people who understand the filter chain. This set covers the questions asked most often across intermediate rounds, using current Spring Security 6 / Spring 6 configuration — the lambda DSL and the SecurityFilterChain bean, not the removed WebSecurityConfigurerAdapter.
How does Spring Security work at a high level?
Spring Security is a chain of servlet filters. A single DelegatingFilterProxy hands each request to a FilterChainProxy, which runs it through an ordered list of security filters — one for authentication, one for authorization, one for CSRF, and so on. Each filter can inspect, reject, or pass the request along.
The mental model to state out loud is that security happens before your controller. By the time a request reaches your @RestController, it has already passed through the filter chain, an Authentication has been established (or the request rejected), and the result is sitting in the SecurityContext. Nothing in your business code runs until the chain approves the request.
Understanding this ordering is what lets you answer follow-ups like "where does JWT validation go?" — it goes in a custom filter you insert into that chain, typically before the UsernamePasswordAuthenticationFilter.
Interview note: A common trap is describing Spring Security as annotations only. Annotations like
@PreAuthorizeare method-level checks that run later; the front door is the servlet filter chain. Saying "it's a filter chain" first signals that you understand the architecture.
How do you configure security in Spring Security 6?
You define a SecurityFilterChain bean and configure it with the lambda DSL. The old WebSecurityConfigurerAdapter was deprecated in 5.7 and removed in 6.0, so overriding configure(HttpSecurity) is no longer the way.
A correct, current configuration looks like this:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
public class SecurityConfig {
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable()) // stateless token API
.cors(cors -> {}) // use the CorsConfigurationSource bean
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/auth/**").permitAll()
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated())
.sessionManagement(sm -> sm
.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.httpBasic(basic -> {});
return http.build();
}
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
Every method takes a lambda that customises one aspect of the chain. http.build() returns the configured SecurityFilterChain. Being able to write this from memory is often the whole question.
Interview note: If you write
WebSecurityConfigurerAdapterin a 2026 interview, expect an immediate correction. Mentioning that you know it was removed — and why component-based config is more testable — turns the trap into a point.
What is the difference between authentication and authorization?
Authentication answers "who are you?" — it verifies credentials and builds an Authentication object. Authorization answers "what may you do?" — it checks that verified principal against access rules. Authentication always happens first; authorization uses its result.
In Spring Security terms, authentication is handled by an AuthenticationManager delegating to AuthenticationProviders, and the successful result is stored in the SecurityContext. Authorization is then enforced two ways: URL-level rules inside authorizeHttpRequests, and method-level rules via annotations such as @PreAuthorize.
The distinction matters because the failure modes differ. Failed authentication returns 401 Unauthorized (we don't know who you are); failed authorization returns 403 Forbidden (we know who you are, but you can't do this). Naming those status codes correctly is a quick credibility signal.
What are UserDetailsService and UserDetails?
UserDetailsService has one method, loadUserByUsername, that Spring calls during authentication to fetch a user by name. It returns a UserDetails — the framework's view of a user: username, hashed password, and granted authorities. You implement UserDetailsService to load users from your database.
@Service
public class DbUserDetailsService implements UserDetailsService {
private final UserRepository users;
public DbUserDetailsService(UserRepository users) {
this.users = users;
}
@Override
public UserDetails loadUserByUsername(String username) {
AppUser u = users.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException(username));
return User.withUsername(u.getUsername())
.password(u.getPasswordHash())
.roles(u.getRoles().toArray(String[]::new))
.build();
}
}
The DaoAuthenticationProvider calls your service, then uses the PasswordEncoder to compare the submitted password against the stored hash. Separating "how do I find a user" (UserDetailsService) from "how do I check the password" (PasswordEncoder) is a clean design point worth stating.
Interview note: Follow-up: "what happens if you return a plaintext password from
UserDetails?" Authentication fails, becauseBCryptPasswordEncoder.matchescompares the raw input against a value it expects to be a bcrypt hash. Passwords must be stored already encoded.
Why use BCryptPasswordEncoder and expose it as a bean?
BCrypt is an adaptive, salted hash: it stores a random salt inside the hash and uses a tunable work factor, so identical passwords produce different hashes and brute-forcing stays expensive as hardware improves. You expose one PasswordEncoder bean so registration and authentication use the same algorithm.
The salt-per-hash property is the part interviewers probe. Because the salt lives in the output string, you do not manage salts yourself, and two users with the same password get different stored values — defeating rainbow tables. The work factor (default strength 10) can be raised as CPUs get faster without changing code elsewhere.
If registration hashed with one encoder and login compared with another, every login would fail — which is exactly why the single shared bean matters.
How do you enable method-level security with @PreAuthorize?
Add @EnableMethodSecurity to a configuration class, then annotate methods with @PreAuthorize (or @PostAuthorize). Spring wraps those beans in a proxy that evaluates a SpEL expression against the current authentication before the method runs.
@Configuration
@EnableMethodSecurity
public class MethodSecurityConfig { }
@Service
public class AccountService {
@PreAuthorize("hasRole('ADMIN')")
public void closeAccount(Long id) { /* ... */ }
@PreAuthorize("#userId == authentication.principal.id or hasRole('ADMIN')")
public Account view(Long userId) { /* ... */ }
}
@EnableMethodSecurity is the Spring Security 6 replacement for the older @EnableGlobalMethodSecurity, and it enables @PreAuthorize/@PostAuthorize by default. The second example shows why method security is powerful: SpEL can reference method arguments and the principal, so you express "owner or admin" rules that URL matching cannot.
Interview note: Trap: because method security is proxy-based, an internal call from one method to another
@PreAuthorizemethod in the same bean bypasses the check — the call does not go through the proxy. This is the same self-invocation limitation as@Transactional.
Form login versus stateless JWT — how do you choose?
Form login uses a server-side session and a JSESSIONID cookie: Spring authenticates once and remembers you via the session. Stateless JWT puts a signed token in the Authorization: Bearer header on every request, so the server keeps no session. Browser-rendered apps favour sessions; APIs and SPAs favour JWT.
With sessions, SessionCreationPolicy stays at its default and the SecurityContext is persisted in the HttpSession. With JWT you set SessionCreationPolicy.STATELESS, add a filter that validates the token and populates the SecurityContext per request, and Spring creates no session at all.
The trade-off is scaling versus revocation. Stateless tokens scale horizontally with no shared session store, but you cannot instantly invalidate a token before it expires without extra machinery (short expiry plus refresh tokens, or a denylist). Naming that trade-off is what makes the answer senior.
Interview note: Follow-up: "where do you put JWT validation?" In a
OncePerRequestFilterinserted beforeUsernamePasswordAuthenticationFilterwithhttp.addFilterBefore(...), so a valid token authenticates the request before the standard filters run.
Why is CSRF disabled for stateless APIs, and what is SecurityContextHolder?
CSRF attacks exploit cookies the browser sends automatically. A stateless API authenticated by a bearer token in a header is not vulnerable, because the browser does not attach the token automatically — so CSRF protection is disabled for token APIs and kept on for cookie-based server-rendered apps. SecurityContextHolder is the thread-local that holds the current Authentication for the request.
CSRF is genuinely needed when a logged-in session cookie rides along with a forged cross-site request; the CSRF token proves the request came from your own page. Remove the ambient-cookie assumption — as a bearer-token API does — and the whole attack disappears, so leaving CSRF on would only add friction.
SecurityContextHolder.getContext().getAuthentication() is how any code retrieves the current principal. It is thread-bound, populated by the filter chain, and cleared at the end of the request.
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String username = auth.getName();
How does CORS relate to Spring Security?
CORS controls which browser origins may call your API; it is enforced by the browser via preflight requests. In Spring Security you enable it with http.cors(...) and supply a CorsConfigurationSource bean listing allowed origins, methods and headers. CORS and CSRF are different concerns and are often confused.
The order matters: Spring Security must handle CORS preflight OPTIONS requests before authorization, which is why enabling CORS inside the filter chain (rather than only via MVC config) is the reliable approach for secured endpoints. A missing or misconfigured CorsConfigurationSource is the classic cause of "it works in Postman but fails in the browser."
Interview note: Trap: "CORS makes my API secure." No — CORS is a browser policy, not server-side authorization. It restricts which web pages can read responses; it does not authenticate anyone. Security still comes from the filter chain and authorization rules.
What interviewers really test
Spring Security questions reward candidates who can move from the filter-chain picture down to a concrete, correct SecurityFilterChain bean and back up to trade-offs like session versus JWT. Interviewers are checking that you use current Spring 6 configuration, that you can explain why CSRF is disabled for token APIs rather than reciting that it is, and that you understand method security is proxy-based with the same self-invocation limitation as @Transactional.
To prepare, build a tiny secured API end to end: a SecurityFilterChain, a database-backed UserDetailsService, BCryptPasswordEncoder, and one @PreAuthorize rule — then add a JWT filter and switch to stateless. The Spring Boot learning path walks through the surrounding concepts, and pairing this with the Spring MVC interview set covers how requests reach your controllers in the first place. When you can wire the chain without notes, a mock interview focused on security is the fastest way to find which follow-up layer you stop at — and push it one deeper.
Frequently Asked Questions
What is the most important Spring Security topic for interviews?
Is WebSecurityConfigurerAdapter still used in Spring Security 6?
Why do we disable CSRF for REST APIs in Spring Security?
What is the difference between authentication and authorization?
How does Spring Security store passwords?
Want to Build Your Career in Java Full Stack with AI?
Join CodeBegun and train with working industry engineers — View the Java Full Stack curriculum

