Quiz: Spring Security
Test your knowledge on Spring Security, JWT, and OAuth2.
30 questions - Click on each question to reveal the answer.
Questions 1-10: Security Fundamentals
Question 1: Which dependency to add for Spring Security?
Answer:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
By default, all routes are protected.
Question 2: What happens when you add Spring Security without configuration?
Answer:
- All routes require authentication
- A login form is displayed
- A
useris created with a generated password (displayed in logs) - CSRF is enabled
Question 3: How to configure security in Spring Boot 3?
Answer:
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/public/**").permitAll()
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.httpBasic(Customizer.withDefaults());
return http.build();
}
}
Question 4: What is the difference between authenticated() and permitAll()?
Answer:
permitAll(): accessible without authenticationauthenticated(): requires an authenticated userhasRole("X"): requires role XhasAuthority("X"): requires authority X
Question 5: How to define in-memory users?
Answer:
@Bean
public UserDetailsService userDetailsService() {
UserDetails user = User.builder()
.username("user")
.password(passwordEncoder().encode("password"))
.roles("USER")
.build();
UserDetails admin = User.builder()
.username("admin")
.password(passwordEncoder().encode("admin"))
.roles("ADMIN")
.build();
return new InMemoryUserDetailsManager(user, admin);
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
Question 6: How to implement UserDetailsService with a database?
Answer:
@Service
public class CustomUserDetailsService implements UserDetailsService {
private final UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) {
User user = userRepository.findByEmail(username)
.orElseThrow(() -> new UsernameNotFoundException("User not found"));
return org.springframework.security.core.userdetails.User.builder()
.username(user.getEmail())
.password(user.getPassword())
.roles(user.getRole().name())
.build();
}
}
Question 7: Why encode passwords?
Answer:
- Security: passwords unreadable if DB compromised
- BCrypt: generates a different hash each time (salt integrated)
- Requirement: Spring Security refuses plain text passwords
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
Question 8: What is the difference between Role and Authority?
Answer:
- Role: automatically prefixed by
ROLE_ - Authority: used as is
// These two are equivalent:
.hasRole("ADMIN") // checks ROLE_ADMIN
.hasAuthority("ROLE_ADMIN")
// Custom authorities
.hasAuthority("READ_USERS")
.hasAuthority("WRITE_USERS")
Question 9: What is CSRF and when to disable it?
Answer: CSRF (Cross-Site Request Forgery) protects against malicious requests.
Disable for stateless REST APIs (JWT):
http.csrf(csrf -> csrf.disable())
Keep enabled for applications with sessions.
Question 10: How to retrieve the connected user?
Answer:
// In a controller
@GetMapping("/me")
public User getCurrentUser(@AuthenticationPrincipal UserDetails userDetails) {
return userService.findByEmail(userDetails.getUsername());
}
// Or via SecurityContextHolder
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String username = auth.getName();
Questions 11-20: JWT
Question 11: What is a JWT?
Answer: JSON Web Token - a token composed of 3 parts:
- Header: algorithm and type
- Payload: claims (data)
- Signature: integrity verification
Format: header.payload.signature (Base64 encoded)
Question 12: What are the standard claims of a JWT?
Answer:
| Claim | Description |
|---|---|
sub | Subject (user) |
iss | Issuer (emitter) |
exp | Expiration |
iat | Issued at |
nbf | Not before |
jti | JWT ID (unique) |
Question 13: How to generate a JWT?
Answer:
@Service
public class JwtService {
@Value("${jwt.secret}")
private String secret;
public String generateToken(UserDetails user) {
return Jwts.builder()
.setSubject(user.getUsername())
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + 86400000))
.signWith(getSigningKey(), SignatureAlgorithm.HS256)
.compact();
}
private Key getSigningKey() {
return Keys.hmacShaKeyFor(Decoders.BASE64.decode(secret));
}
}
Question 14: How to validate a JWT?
Answer:
public boolean isTokenValid(String token, UserDetails userDetails) {
try {
Claims claims = Jwts.parserBuilder()
.setSigningKey(getSigningKey())
.build()
.parseClaimsJws(token)
.getBody();
String username = claims.getSubject();
Date expiration = claims.getExpiration();
return username.equals(userDetails.getUsername())
&& !expiration.before(new Date());
} catch (JwtException e) {
return false;
}
}
Question 15: How to implement a JWT filter?
Answer:
@Component
public class JwtAuthFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain chain) {
String header = request.getHeader("Authorization");
if (header != null && header.startsWith("Bearer ")) {
String token = header.substring(7);
String username = jwtService.extractUsername(token);
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails user = userDetailsService.loadUserByUsername(username);
if (jwtService.isTokenValid(token, user)) {
UsernamePasswordAuthenticationToken auth =
new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(auth);
}
}
}
chain.doFilter(request, response);
}
}
Question 16: How to configure the JWT filter?
Answer:
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable())
.sessionManagement(session ->
session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/auth/**").permitAll()
.anyRequest().authenticated()
)
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
Question 17: What is a Refresh Token?
Answer: A long-lived token to obtain new access tokens without re-login:
- Access Token: short-lived (15min-1h)
- Refresh Token: long-lived (7-30 days)
// Refresh endpoint
@PostMapping("/refresh")
public TokenResponse refresh(@RequestBody RefreshRequest request) {
String refreshToken = request.getRefreshToken();
// Validate and generate new access token
}
Question 18: How to securely store the JWT secret?
Answer:
- Environment variables
- Vault (HashiCorp Vault)
- AWS Secrets Manager
- Spring Cloud Config (encrypted)
# NEVER commit the secret!
jwt:
secret: ${JWT_SECRET}
Question 19: How to invalidate a JWT?
Answer: JWTs are stateless, so not directly revocable. Solutions:
- Blacklist: store revoked tokens (Redis)
- Short expiration: tokens valid for a short time
- User versioning: invalidate on password change
Question 20: How to secure endpoints with annotations?
Answer:
@EnableMethodSecurity
@Configuration
public class SecurityConfig { }
@RestController
public class UserController {
@PreAuthorize("hasRole('ADMIN')")
@GetMapping("/admin/users")
public List<User> getAllUsers() { }
@PreAuthorize("#id == authentication.principal.id or hasRole('ADMIN')")
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id) { }
}
Questions 21-30: OAuth2 and Advanced Security
Question 21: What is OAuth2?
Answer: Authorization protocol allowing an application to access a user's resources via a third-party provider (Google, GitHub, etc.) without sharing the password.
Question 22: What are the roles in OAuth2?
Answer:
- Resource Owner: the user
- Client: the application
- Authorization Server: Google, GitHub...
- Resource Server: protected API
Question 23: How to configure OAuth2 with Google?
Answer:
spring:
security:
oauth2:
client:
registration:
google:
client-id: ${GOOGLE_CLIENT_ID}
client-secret: ${GOOGLE_CLIENT_SECRET}
scope: openid, profile, email
http.oauth2Login(Customizer.withDefaults());
Question 24: How to customize OAuth2 login success?
Answer:
http.oauth2Login(oauth -> oauth
.successHandler((request, response, authentication) -> {
OAuth2User oauthUser = (OAuth2User) authentication.getPrincipal();
userService.processOAuthUser(oauthUser);
response.sendRedirect("/dashboard");
})
);
Question 25: What is CORS?
Answer: Cross-Origin Resource Sharing - allows requests from other domains:
@Configuration
public class CorsConfig {
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowedOrigins(List.of("http://localhost:3000"));
config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE"));
config.setAllowedHeaders(List.of("*"));
config.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return source;
}
}
Question 26: How to add security headers?
Answer:
http.headers(headers -> headers
.contentSecurityPolicy(csp -> csp.policyDirectives("default-src 'self'"))
.frameOptions(frame -> frame.deny())
.xssProtection(xss -> xss.enable())
);
Question 27: How to limit login attempts?
Answer: Implement a rate limiter:
@Component
public class LoginAttemptService {
private final LoadingCache<String, Integer> attemptsCache;
public void loginFailed(String ip) {
int attempts = attemptsCache.get(ip);
attemptsCache.put(ip, attempts + 1);
}
public boolean isBlocked(String ip) {
return attemptsCache.get(ip) >= MAX_ATTEMPTS;
}
}
Question 28: How to audit secure access?
Answer:
@Component
public class SecurityAuditListener {
@EventListener
public void onAuthSuccess(AuthenticationSuccessEvent event) {
log.info("Login successful: {}", event.getAuthentication().getName());
}
@EventListener
public void onAuthFailure(AuthenticationFailureBadCredentialsEvent event) {
log.warn("Login failed: {}", event.getAuthentication().getName());
}
}
Question 29: How to test security?
Answer:
@WebMvcTest(UserController.class)
@Import(SecurityConfig.class)
class UserControllerSecurityTest {
@Test
@WithMockUser(roles = "ADMIN")
void adminCanAccessAdminEndpoint() {
mockMvc.perform(get("/admin/users"))
.andExpect(status().isOk());
}
@Test
@WithMockUser(roles = "USER")
void userCannotAccessAdminEndpoint() {
mockMvc.perform(get("/admin/users"))
.andExpect(status().isForbidden());
}
}
Question 30: What are the best practices for Spring security?
Answer:
- Always encode passwords (BCrypt)
- Use HTTPS in production
- Configure CORS strictly
- Implement rate limiting
- Validate all inputs
- Log security events
- Use strong secrets and externalize them
- Regularly update dependencies
Score
| Score | Level |
|---|---|
| 27-30 | Excellent - Security mastered |
| 21-26 | Good - Some revisions needed |
| 15-20 | Average - Review the chapters |
| Less than 15 | Needs improvement |