In today's world of cloud-native applications and RESTful APIs, ensuring your application is secure is not optional — it's mandatory. Spring Security is the standard security framework for securing Java-based web applications built with the Spring ecosystem.
This blog explains what Spring Security is, why it's important, and how it works under the hood, with examples and configuration guidance.
What is Spring Security?
Spring Security is a powerful, customizable framework for handling authentication, authorization, and protection against common attacks like CSRF, session fixation, clickjacking, and more.
It integrates seamlessly with Spring Boot and provides both declarative and programmatic security configurations.
You can secure:
- Web applications with form login
- REST APIs with stateless token-based authentication
- Method-level access control using annotations
Why Use Spring Security?
- Integrated with Spring Boot: Works out-of-the-box with Spring Boot auto-configuration
- Highly customizable: Can adapt to form login, OAuth2, JWT, LDAP, and more
- Secure by default: Applies default security rules like login form and user roles
- Comprehensive: Covers everything from login to access control to session management
Core Concepts of Spring Security
Authentication
Authentication is the process of verifying who the user is. In Spring Security, this is handled using AuthenticationManager
and implemented via user credentials (username/password).
Authorization
Authorization determines what resources a user can access. It is role- or permission-based and enforced using filters or annotations.
Filter Chain
Spring Security runs on a chain of filters. Each filter has a specific job such as checking credentials, verifying access, or protecting against CSRF.
UserDetailsService
This interface loads user-specific data for authentication. You can provide your own custom implementation to fetch users from a database.
How Spring Security Works Internally
Here's a simplified request lifecycle with Spring Security:
- User makes a request (e.g., logs in via a form)
- AuthenticationFilter intercepts and validates credentials
- Upon success, an
Authentication
object is created and stored in theSecurityContext
- Subsequent requests use the session/token to authorize the user
- If credentials or roles are invalid, access is denied
Default Spring Boot Security
When you add spring-boot-starter-security
to your project, Spring Boot automatically enables:
- A default login page at
/login
- A generated default user with username:
user
- A console-generated random password
- All endpoints restricted by default
Dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
In-Memory User Authentication
For testing or demo purposes, you can define users in memory using Java config.
@Bean
public UserDetailsService userDetailsService() {
UserDetails user = User.withDefaultPasswordEncoder()
.username("admin")
.password("password")
.roles("ADMIN")
.build();
return new InMemoryUserDetailsManager(user);
}
Custom Login Page
The default login page is great for testing but not suitable for production. To build a custom login page, create a simple HTML form and configure Spring Security to use it.
login.html
<form method="post" action="/login">
<input type="text" name="username" />
<input type="password" name="password" />
<button type="submit">Login</button>
</form>
Security Configuration:
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests()
.requestMatchers("/admin/**").hasRole("ADMIN")
.requestMatchers("/user/**").hasRole("USER")
.requestMatchers("/login", "/register").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/dashboard")
.permitAll()
.and()
.logout()
.logoutSuccessUrl("/login?logout")
.permitAll();
return http.build();
}
}
This tells Spring to use your custom login form and redirect users upon successful authentication.
Role-Based Access Control
Spring Security allows you to define roles for different types of users.
Roles typically start with ROLE_
(e.g., ROLE_USER
, ROLE_ADMIN
).
Assign Roles:
User.withUsername("admin")
.password("{noop}admin123")
.roles("ADMIN")
.build();
Use hasRole()
, hasAuthority()
, or access()
to control access in your config.
.requestMatchers("/admin/**").hasRole("ADMIN")
.requestMatchers("/api/**").hasAnyRole("ADMIN", "API_USER")
Enabling Method-Level Security
With method-level security, you can secure service or controller methods using annotations like:
@PreAuthorize
, @PostAuthorize
, @Secured
, or @RolesAllowed
.
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Configuration
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {}
Examples:
@PreAuthorize("hasRole('ADMIN')")
public void deleteUser(Long id) { ... }
@Secured("ROLE_USER")
public void viewProfile() { ... }
application.properties Configuration
Some configurations can be defined in application.properties
:
spring.security.user.name=admin
spring.security.user.password=admin123
spring.security.user.roles=ADMIN
server.error.whitelabel.enabled=false
These settings are useful for quick testing or prototyping.
Password Encoding
Spring Security does not allow plain text passwords in production by default.
Use a password encoder like BCryptPasswordEncoder
.
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
User.builder()
.username("admin")
.password(passwordEncoder().encode("admin123"))
.roles("ADMIN")
.build();
Stateless Authentication with JWT
In REST APIs, sessions are not preferred. Instead, you use JWT (JSON Web Tokens) for stateless security.
JWT contains all the user information encoded and signed by the server. Once a user logs in, the server returns a token that must be passed in the Authorization
header of each request.
Sample Token:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
The backend validates the token on each request. No session is maintained server-side.
Configuring JWT in Spring Boot
To integrate JWT with Spring Security:
- Create a
JwtUtil
class to generate and validate tokens - Create a custom
OncePerRequestFilter
to intercept all requests - Inject user details using
UsernamePasswordAuthenticationToken
- Disable session and enable stateless mode in
HttpSecurity
http.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeHttpRequests()
.requestMatchers("/api/auth/**").permitAll()
.anyRequest().authenticated();
Spring Security for REST APIs
For REST APIs, use stateless JWT or OAuth2 flows. Avoid form login and session-based auth.
Key practices:
- Stateless security: no session, use JWT
- Custom
AuthenticationFilter
for login endpoint - Custom
ExceptionHandler
to handle auth failures - Return HTTP 401/403 as needed
CSRF Protection
CSRF (Cross-Site Request Forgery) is an attack where the browser makes an unauthorized request on behalf of a user. Spring Security enables CSRF protection by default for web applications.
For REST APIs, you can safely disable it:
http.csrf().disable();
If you're using cookies for sessions in a web app, keep CSRF enabled.
CORS Configuration
CORS (Cross-Origin Resource Sharing) allows your frontend and backend to interact across domains.
Spring Boot Java Config:
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:3000")
.allowedMethods("*")
.allowedHeaders("*");
}
};
}
Ensure CORS is handled before Spring Security filter chain.
Best Practices for Spring Security
- Always use HTTPS in production
- Store passwords with
BCrypt
orArgon2
- Keep endpoints like
/actuator
,/h2-console
protected - Use
@PreAuthorize
and@PostAuthorize
for method-level protection - Sanitize inputs and avoid open redirects
- Limit login attempts to prevent brute-force
Final Summary
Spring Security is a must-have for any production-level Spring Boot application. From basic authentication to complex token-based security for APIs, it provides a full toolbox for developers.
We covered:
- Spring Security internals: filters, context, authentication
- Custom login, roles, and method-level security
- JWT for stateless APIs, CSRF and CORS configuration
By mastering these concepts, you can build secure, scalable Java web applications that follow modern security standards.
0 Comments