📘 Premium Read: Access my best content on Medium member-only articles — deep dives into Java, Spring Boot, Microservices, backend architecture, interview preparation, career advice, and industry-standard best practices.
✅ Some premium posts are free to read — no account needed. Follow me on Medium to stay updated and support my writing.
🎓 Top 10 Udemy Courses (Huge Discount): Explore My Udemy Courses — Learn through real-time, project-based development.
▶️ Subscribe to My YouTube Channel (172K+ subscribers): Java Guides on YouTube
Spring Security is a robust and highly customizable framework that helps developers secure Java applications. Whether you’re building REST APIs or web apps, Spring Security gives you powerful tools to handle authentication, authorization, and user management.
But what actually happens behind the scenes when a user logs in? How does Spring know who the user is and what they can access?
In this article, we’ll break down the core components of Spring Security, understand how they work together, and walk through a real authentication flow.
What is Spring Security?
Spring Security is a part of the Spring ecosystem that focuses on providing authentication, authorization, and protection against common exploits such as CSRF, session fixation, clickjacking, etc.
It can:
- Authenticate users (who are you?)
- Authorize requests (what are you allowed to do?)
- Integrate with databases, LDAP, OAuth2, JWT, etc.
In short, Spring Security is your first line of defense in any Java/Spring-based web application.
🏃♂️ Key Spring Security Components
Before diving into the internal flow, let’s understand the core building blocks of Spring Security. These components make up the foundation of how the security system functions.
✨ Principal
Represents the currently logged-in user.
You can get it using:
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
Object principal = auth.getPrincipal();
Usually, this is a UserDetails
object.
✔️ Authentication
Means confirming the identity of a user using credentials like username and password.
public interface Authentication extends Principal {
Object getCredentials();
Object getPrincipal();
boolean isAuthenticated();
}
⛔ Authorization
Defines what the authenticated user is allowed to do. For example, can the user access /admin
?
Spring uses roles and authorities to enforce these rules.
🔑 GrantedAuthority
Represents a permission granted to the principal. Roles like ROLE_USER
, ROLE_ADMIN
are examples.
Collection<? extends GrantedAuthority> getAuthorities();
📌 AuthenticationManager
The controller of the authentication process. It decides whether authentication is successful.
It exposes the method:
Authentication authenticate(Authentication authentication) throws AuthenticationException;
Often used with in-memory users, database users, or third-party login systems.
🧱 AuthenticationProvider
It connects Spring Security with your user data source (like DB or LDAP).
You can have multiple providers for different types of logins.
boolean supports(Class<?> authentication);
Authentication authenticate(Authentication authentication);
💊 Authentication Object
Created during login, this object holds the credentials and principal.
Before login:
- Username and password (credentials only)
After login:
- Fully populated with user info and authorities
📄 UserDetails
A core object in Spring Security. It contains the user’s credentials and roles.
public interface UserDetails {
String getUsername();
String getPassword();
Collection<? extends GrantedAuthority> getAuthorities();
}
🔎 UserDetailsService
Used to load user data from a source (DB, memory, etc.).
You implement it like this:
@Override
public UserDetails loadUserByUsername(String username) {
return new User("ramesh", "{noop}1234", List.of(new SimpleGrantedAuthority("ROLE_USER")));
}
This is injected into DaoAuthenticationProvider
.
🛡️ How Spring Security Works Internally (Authentication Flow)
Spring Security is not just about login pages and roles — under the hood, it follows a well-defined authentication flow that makes it modular, pluggable, and secure.
Let’s walk through the authentication process based on the diagram:

🔐 Step-by-Step Spring Security Authentication Flow
1️⃣ Authentication Filter
- Entry point for any authentication request (e.g., login form, JWT token, Basic Auth).
- Captures the user’s credentials from the request (username/password, token, etc.)
- Creates an
Authentication
object with just the credentials (not yet authenticated). - Passes this object to the AuthenticationManager.
🧠 Example: UsernamePasswordAuthenticationFilter
, BearerTokenAuthenticationFilter
2️⃣ AuthenticationManager
- The main component that coordinates the authentication process.
- Calls
.authenticate()
method on each registeredAuthenticationProvider
until one supports the authentication type.
📌 Think of it as a dispatcher that finds the right provider to handle the request.
3️⃣ AuthenticationProvider(s)
Each AuthenticationProvider
is responsible for checking credentials for a specific type of Authentication
(like username-password, LDAP, JWT).
Two key methods:
supports()
→ Can I handle this Authentication type?authenticate()
→ Validate the credentials and return a fully authenticatedAuthentication
object.
If successful:
- It creates a new
Authentication
object with the principal (UserDetails) and roles. - Sends it back to
AuthenticationManager
.
4️⃣ UserDetailsService
Called by the AuthenticationProvider
(usually DaoAuthenticationProvider
).
Loads the user info by username from a database or in-memory store.
Returns a UserDetails
object, which includes:
- username
- password (hashed)
- roles/authorities
- isAccountNonExpired, isEnabled, etc.
🧠 You implement this with:
@Override
public UserDetails loadUserByUsername(String username) {
return userRepository.findByUsername(username)
.map(user -> new User(user.getUsername(), user.getPassword(), List.of(new SimpleGrantedAuthority("ROLE_USER"))))
.orElseThrow(() -> new UsernameNotFoundException("User not found"));
}
5️⃣ Authentication Object (Principal)
Once verified:
- A new
Authentication
object is created — this time with full principal (UserDetails) info and authorities. - This is marked as authenticated.
It flows back from:
➡️ AuthenticationProvider
➡️ AuthenticationManager
➡️ AuthenticationFilter
6️⃣ SecurityContext
Finally, Spring Security stores the authenticated Authentication
object in the SecurityContext
, which is tied to the current thread/request.
You can access it anywhere in your code like:
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String username = auth.getName();
🧾 Summary Flow

✅ Final Thoughts
Spring Security’s internal design:
- Is modular: plug in custom filters, providers, services
- Is secure by default
- Can support multiple authentication types (form login, JWT, LDAP, OAuth2)
Once you understand howAuthenticationManager
andAuthenticationProvider
interact, writing custom login logic or token-based auth becomes much easier.
Comments
Post a Comment
Leave Comment