Spring Security - A Quick Overview

Sujal SamaiSujal Samai
8 min read

🔰 Introduction to Spring Security

In today’s world, securing applications is more critical than ever. Whether you're building a simple web app or a complex enterprise system, ensuring that only the right users can access the right resources is a fundamental requirement. That’s where Spring Security comes in.

Spring Security is a powerful and highly customizable authentication and access-control framework for Java applications, particularly those built with Spring. It handles common security concerns such as login, logout, password management, role-based access, and protection against common vulnerabilities like CSRF and session fixation.

What makes Spring Security especially useful is that it integrates seamlessly with the rest of the Spring ecosystem and allows you to configure everything from a simple login form to complex OAuth2 setups with minimal effort.

🔐 Authentication and Authorization

Spring Security has two main goals: Authentication and Authorization.

Authentication is the process of verifying the user’s identity i.e., who the user is — usually via username and password. On the other hand, Authorization is about checking what an authenticated user is allowed to do, what the user can access and what they cannot.

Spring Security is a very powerful framework that works out of the box in your Spring Application and can handle both Authentication & Authorization. And it is not limited to only login Pages, it can also handle things like:

  • Password Encoding

  • Role based access control

  • Session Management

  • OAuth2.0, JWT & a lot more..

All these are managed by Spring Security with sensible defaults while also giving full control to configure and change them as you like.

Let’s take a small example to check the usability of Spring Security:

Suppose you have a Spring Boot application with a simple REST endpoint:

@RestController
public class HelloController {

    @GetMapping("/hello")
    public String sayHello() {
        return "Hello, authenticated user!";
    }
}

Make sure to add this maven dependency in your pom.xml 👇

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

Now, with just a dependency of Spring Security, this endpoint becomes secured automatically! Without writing any security code, Spring Security prompts users to log in using a default login page. Behind the scenes, it sets up a default user with a generated password (printed in the console when the app runs).

🔍 Filters

Filters are the first line of defense for your Spring Application. Spring Security uses a chain of filters to intercept and process every incoming HTTP request before it reaches your controller (like a bouncer checking people before they enter a club).

These filters handle different parts of the security process such as:

  • Checking authentication (Is the user logged in?)

  • Checking authorization (Does the user have permission?)

  • Preventing CSRF attacks

  • Managing sessions

  • Redirecting to login/logout pages

Let’s assume you set up Spring Security correctly and then boot up your web application. You’ll see the following log message:

2020-02-25 10:24:27.875  INFO 11116 --- [           main] o.s.s.web.DefaultSecurityFilterChain     : Creating filter chain: any request, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@46320c9a, org.springframework.security.web.context.SecurityContextPersistenceFilter@4d98e41b, org.springframework.security.web.header.HeaderWriterFilter@52bd9a27, org.springframework.security.web.csrf.CsrfFilter@51c65a43, org.springframework.security.web.authentication.logout.LogoutFilter@124d26ba, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@61e86192, org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@10980560, org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter@32256e68, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@52d0f583, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@5696c927, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@5f025000, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@5e7abaf7, org.springframework.security.web.session.SessionManagementFilter@681c0ae6, org.springframework.security.web.access.ExceptionTranslationFilter@15639d09, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@4f7be6c8]|

When you add Spring Security to your application, it doesn’t just add a single filter to handle authentication and authorization. Instead, it sets up a chain of filters15 (or more) filters — each with its own responsibility in the security process.

So when an HTTP request comes into your application, it doesn’t go straight to your @RestController. Instead, it first passes through this security filter chain.

Each filter in the chain performs a specific task — like checking if the user is authenticated, handling login, enforcing roles, protecting against CSRF attacks, etc. These filters are executed in a specific order, from top to bottom, and the order matters. Some filters depend on the outcome of previous ones.

Only after the request successfully makes it through all these filters will it reach your controller and be processed normally.

Here’s the explanations for a few of those filters:

🔑 1. SecurityContextPersistenceFilter

  • What it does: Restores security info (like who’s logged in) at the beginning of a request and saves it back at the end.

  • Think of it like: Opening and closing a secure session for each request.

🔐 2. UsernamePasswordAuthenticationFilter

  • What it does: Handles login form submissions. It checks the username and password.

  • Think of it like: The login gatekeeper that verifies your credentials.

📄 3. BasicAuthenticationFilter

  • What it does: Supports HTTP Basic authentication (passing credentials in headers).

  • Think of it like: An alternative to form login — often used for APIs.

👤 4. AnonymousAuthenticationFilter

  • What it does: Assigns a default “anonymous” identity to users who haven’t logged in.

  • Think of it like: Giving a guest badge to someone who didn’t check in at the front desk.

🚪 5. LogoutFilter

  • What it does: Listens for logout requests and clears the session or authentication data.

  • Think of it like: The system that logs you out and ends your session securely.

⚠️ 6. ExceptionTranslationFilter

  • What it does: Catches security errors and redirects users (like to the login page or shows access denied).

  • Think of it like: A security error handler that knows where to send you when access fails.

🛡️ 7. CsrfFilter

  • What it does: Protects your app from CSRF attacks by checking for CSRF tokens in form submissions.

  • Think of it like: A bodyguard that checks for a valid ticket before letting the request in.

🧠 8. FilterSecurityInterceptor

  • What it does: The final gatekeeper — it checks if the user has permission (based on roles or rules).

  • Think of it like: The bouncer at the last door who double-checks your access rights.

💡
You can even create your custom filters and place them at any position in the filter chain.

🌊 Authentication Flow

When a request hits your Spring Application, Spring Security intercepts using a Filter Chain like a gatekeeper to decide, whether the user is authenticated and if they have the permission to access the asked endpoint. Behind the scenes, it uses a UserDetailsService to load information, typically from a database.

The flow is like this:

  1. User sends their login credentials

  2. Spring Security captures and filters the request. Specifically, it reaches the UsernamePasswordAuthenticationFilter.

  3. UsernamePasswordAuthenticationFilter creates a UsernamePasswordAuthenticationToken using the submitted credentials. At this point, user in unathenticated.

     new UsernamePasswordAuthenticationToken("john", "password123");
    
  4. The filter passes the token to the AuthenticationManager.

     authenticationManager.authenticate(authenticationToken);
    
  5. AuthenticationManager delegates to an AuthenticationProvider, usually a DaoAuthenticationProvider, which calls your UserDetailsService to fetch the user information. Users have to implement this UserDetailsService to load user information.

  6. The loaded UserDetails has a stored (encoded) password. Spring then uses the PasswordEncoder to compare the raw password with the stored one:

     passwordEncoder.matches("password123", user.getPassword());
    
  7. Spring Security creates a new authenticated Authentication object and stores it in the SecurityContext.

    From this point on, Spring knows who the user is for the current session/request.

     SecurityContextHolder.getContext().setAuthentication(authenticatedToken);
    
  8. Now that authentication is complete, the request continues through the filter chain and reaches your @RestController.

💡Tip: If you would like to set up OAuth 2.0 and let your user access the endpoints through their google account. Add this in your application.yml file.

spring.security.oauth2.client.registeration.google.client-id: your-client-id
spring.security.oauth2.client.registeration.google.client-secret: your-client-secret

Spring will automatically generate appropriate login page and redirect your users to Google authentication page and handle the callback.

🔐 CSRF in Spring Security

CSRF is an attack where a malicious website tricks a logged-in user into performing unwanted actions on another site where they're authenticated (like submitting a form or making a transfer).

Spring Security enables CSRF protection by default for web apps (especially forms). It works by generating a CSRF token and expecting it in each state-changing request (like POST, PUT, DELETE). If the token is missing or invalid → the request is rejected.

For stateless APIs (e.g., REST APIs using JWT), CSRF is usually disabled:

javaCopyEdithttp.csrf().disable();

Because APIs are typically consumed by trusted clients and don’t use cookies for auth.

🌐 CORS in Spring Security

CORS is a browser security feature that controls which origins (domains) are allowed to access resources from your server. If you’re making an AJAX request from http://frontend.com to http://backend.com, the browser checks CORS rules. Without proper CORS, the browser blocks the request, even if the backend is running and working fine.

Spring Security marks CORS as disabled by default and allows all origins to access the endpoints. This is because CORS is generally handled by the browsers, you need to specifically tell Spring that you need the CORS filtration too. For doing this, you can do the following:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
        .cors().configurationSource(corsConfigurationSource())
        .and()
        .csrf().disable(); // Often disabled for APIs

    return http.build();
}

@Bean
public CorsConfigurationSource corsConfigurationSource() {
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowedOrigins(List.of("http://frontend.com"));
    config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE"));
    config.setAllowedHeaders(List.of("*"));

    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", config);
    return source;
}

✍️ Annotations

Lastly, Spring Security provides several powerful annotations to help you control access at the method level or class level, in a declarative and clean way. Here's a list of the most important ones — explained simply.

  1. @EnableWebSecurity - Enables Spring Security’s configuration support and integrates the security filter chain.

  2. @PreAuthorize - Runs before the method executes — checks if the user has the required role or permission.

  3. @PostAuthorize - Runs after the method executes — usually checks the result of the method for access.

  4. @Secured - Restricts access based on roles (simpler alternative to @PreAuthorize).

  5. @RolesAllowed - Similar to @Secured — specifies allowed roles, but uses the JSR-250 standard.

🎉 Wrapping It Up

Spring Security might seem like a maze at first — filters, tokens, annotations, oh my! 😅 But once you get the hang of it, it’s like having a security superhero guarding your app 24/7. 🦸‍♂️🛡️

From locking down routes, verifying users, to blocking sneaky CSRF attacks and cross-origin drama — it’s got your back. 🙌

So now that you’ve seen how the filter chain works, how authentication flows, and how to sprinkle in those handy annotations, you’re all set to build safer, smarter apps. Go forth and secure all the things! 🚀

Thank you! See you in the next blog, stay tuned 🤖

1
Subscribe to my newsletter

Read articles from Sujal Samai directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Sujal Samai
Sujal Samai

I am a Frontend Developer & a pre-final year student, currently enrolled at Medi-Caps University, Indore.