Spring Security
Spring Security is a powerful and highly customizable authentication and access-control framework that serves as the de-facto standard for securing Spring-based Java applications.[1] It provides comprehensive support for authentication, authorization, and protection against common web attacks such as session fixation, clickjacking, and cross-site request forgery.[2] Originating in late 2003 as the Acegi Security System for Spring—a standalone security framework for J2EE applications—it was integrated into the Spring portfolio toward the end of 2007 and rebranded as Spring Security.[3]
At its core, Spring Security employs a filter-based architecture that integrates seamlessly with Servlet containers through the DelegatingFilterProxy, allowing it to intercept HTTP requests and apply security constraints before they reach the application logic.[4] The framework's Security Filter Chain, managed by FilterChainProxy, delegates requests to specific chains of filters based on URL patterns, enabling fine-grained control over authentication flows (e.g., via UsernamePasswordAuthenticationFilter or BasicAuthenticationFilter) and authorization decisions.[4] This modular design supports both imperative (Servlet-based) and reactive (WebFlux-based) environments, with first-class integration into other Spring projects like Spring Boot, Spring MVC, and Spring Data for streamlined configuration and deployment.[2]
Spring Security emphasizes configurability, allowing developers to use annotation-driven security (e.g., @PreAuthorize for method-level access control), XML-based declarations, or Java-based setups to enforce role-based or attribute-based policies.[4] As of November 2025, the latest stable release is version 7.0.0, which requires Java 17+ and Spring Framework 7.0+, incorporating enhancements for OAuth 2.0, SAML, and JWT support while maintaining backward compatibility for enterprise-scale applications.[1]
History and Development
Origins and Early Versions
Spring Security originated in late 2003 as the Acegi Security System for Spring, developed by Ben Alex to provide a flexible, open-source security framework tailored for Spring-based applications. This project addressed gaps in Java EE security standards, such as the Java Authentication and Authorization Service (JAAS), by offering more comprehensive support for declarative security in POJO-oriented architectures rather than relying solely on container-managed mechanisms.[5]
Acegi Security's first public release occurred in March 2004 under the Apache License 2.0, with core features centered on declarative security implemented through Spring's Aspect-Oriented Programming (AOP) proxies for method-level interception and access control. Ben Alex led the development, and the framework quickly gained traction within the Spring community for its superior flexibility compared to traditional J2EE container security, enabling easier customization and integration without vendor lock-in.
In early 2007, the project underwent a significant transition. On January 25, 2007, Ben Alex announced the rebranding to Spring Security on the official Spring blog, aiming to formalize its alignment with the Spring portfolio and enhance its visibility and support.[6] Acegi Security became an official Spring subproject toward the end of 2007, culminating in the release of Spring Security version 2.0 in April 2008, which marked the first fully integrated version under the new name.[7]
Major Releases and Evolution
Spring Security's major releases have marked significant advancements in integration with the Spring ecosystem, adoption of modern security standards, and configuration paradigms. The project rebranded from Acegi Security and achieved its first official release as Spring Security 2.0.0 on April 15, 2008, which fully integrated the framework as a core Spring module, replacing the standalone Acegi approach with seamless dependency injection and aspect-oriented programming support.[7] This version introduced enhanced method-level security and initial support for RESTful services, laying the groundwork for broader adoption within Spring applications.[8]
Subsequent releases built on this foundation by simplifying configuration and aligning with evolving Java standards. Spring Security 3.0.0, released on December 23, 2009, introduced XML namespace configuration for declarative setup, reducing boilerplate code and enabling easier integration with Spring's application context.[9] It also added support for the Spring Expression Language (SpEL) in security expressions, allowing dynamic authorization rules, and marked a shift toward annotation-based configurations in later 3.x updates, such as @PreAuthorize and @PostAuthorize for method security.[10]
By Spring Security 4.0.0, released on March 26, 2015, the framework incorporated Java 8 features like lambda expressions and streams for more concise security expressions and testing utilities.[11] This version provided native support for Servlet 3.0 asynchronous processing, improving performance in web applications, and enhanced CSRF protection with improved token handling. It also deprecated certain legacy configuration options, encouraging migration to Java-based setups over XML.[11]
Spring Security 5.0.0, released on November 28, 2017, aligned closely with Spring Framework 5, introducing reactive security support via Spring WebFlux for non-blocking applications and comprehensive OAuth 2.0 resource server capabilities.[12] Reactive modules became a core part of the framework, though optional for traditional servlet-based apps, and Java configuration was firmly established as the preferred method, with XML support marked for future deprecation. The release emphasized modern authentication protocols, including SAML 2.0 improvements.[13]
The 6.0 series, with its general availability announced on November 21, 2022, represented a major overhaul to meet contemporary security requirements, requiring Java 17 and Jakarta EE 9 as baselines for better performance and security.[14] It established OAuth 2.1 as the default baseline, incorporating stricter client authentication and proof-key-for-code-exchange (PKCE) enhancements, while adopting modern cryptographic standards such as PBKDF2 for password hashing by default. XML namespace configuration was deprecated in favor of Java config and builder patterns, with removal planned for version 7.0.[14]
As of November 2025, Spring Security maintains parallel branches for compatibility, with the 5.x series receiving security patches alongside the active 6.x line, allowing gradual migrations for legacy applications. The latest stable release is version 7.0.0, issued on November 17, 2025, which introduces support for multi-factor authentication via annotations such as @EnableGlobalMultiFactorAuthentication and removes deprecated XML namespace support entirely, signaling further evolution toward annotation-driven and reactive-first security models. The latest in the 6.x branch is 6.5.7, also released on November 17, 2025, providing maintenance updates and compatibility with Spring Framework 6.2.[15][16]
Overview and Core Architecture
Fundamental Components
Spring Security's fundamental components provide the foundational building blocks for implementing authentication and authorization in Java applications, enabling developers to secure both web and non-web contexts through a modular and extensible architecture. These components include core classes and interfaces that manage user identity, permissions, and security decisions, adhering to established security principles to ensure robust protection without unnecessary complexity.[17]
At the heart of this architecture is the SecurityContextHolder, a utility class responsible for storing the details of the current authentication in a thread-bound manner. By default, it uses a ThreadLocal strategy to propagate the security context across method calls within the same thread, making authentication information accessible throughout the application's execution flow. This design allows seamless integration in multi-threaded environments typical of server-side applications, though it requires careful handling in asynchronous scenarios. For such cases, developers can configure alternative modes, such as MODE_INHERITABLETHREADLOCAL, which enables the security context to be inherited by child threads created from the parent thread, ensuring continuity in security checks during parallel processing.[17]
The SecurityContext held by SecurityContextHolder contains an Authentication object, which represents the principal (typically a user) and encapsulates their credentials and granted permissions. This interface serves as the central representation of a user's identity post-authentication, storing details like the principal's name, authenticated status, and a collection of authorities. In non-web contexts, such as standalone Java applications or scheduled tasks, the Authentication object facilitates method-level security by providing the necessary identity information without relying on HTTP-specific mechanisms. The Authentication object is immutable once populated, promoting thread safety and preventing unauthorized modifications during runtime.[17]
Supporting authentication is the UserDetailsService interface, which defines a contract for loading user-specific data, including username, password, and authorities, from a persistent store like a database or in-memory repository. Implementations of this service are invoked by authentication providers to retrieve and validate user details during the login process, allowing customization for various backends while maintaining a standardized API. This component decouples user data management from the core authentication logic, enabling flexible integration with external identity providers.[18]
For processing authentication requests, the AuthenticationManager interface acts as a delegate, coordinating multiple AuthenticationProvider implementations to validate credentials and return a fully populated Authentication object upon success. It supports pluggable providers for diverse authentication schemes, ensuring that the framework can handle complex scenarios without tight coupling to specific mechanisms. In web applications, this manager initializes the Authentication object stored in the SecurityContextHolder; in non-web contexts, it similarly populates the context for subsequent authorization checks.[17]
Authorization decisions rely on the AccessDecisionManager interface, which evaluates whether an authenticated principal has sufficient permissions to access a protected resource by consulting a set of voters against the Authentication object's authorities. This manager aggregates votes from configurable strategies, such as affirmative, consensus, or unanimous models, to determine access grants or denials. Permissions are represented through the GrantedAuthority interface, which encapsulates fine-grained roles or privileges assigned to the principal, typically as strings like "ROLE_USER" or custom scopes. These authorities enable precise control, aligning with the principle of least privilege by granting only the minimal permissions necessary for a user's role, thereby reducing the attack surface in both web and non-web environments.[19][19]
The interplay among these components ensures a cohesive security model: the SecurityContextHolder provides global access to the Authentication object, which is populated via the AuthenticationManager and UserDetailsService, while the AccessDecisionManager uses GrantedAuthority instances from that object to enforce access controls. In web contexts, this foundation supports HTTP-based security; in non-web scenarios, it underpins annotation-driven or programmatic checks, offering consistent behavior across application types. These components are orchestrated within the security filter chain for servlet-based applications, where they integrate with request processing.[17][19]
Security Filter Chain Mechanics
Spring Security's servlet-based architecture relies on a chain of filters to intercept and process HTTP requests, ensuring security constraints are applied before reaching the application logic. The DelegatingFilterProxy serves as the entry point, integrating Spring Security into the servlet container by delegating requests to the Spring-managed FilterChainProxy bean. This proxy then routes the request to one or more SecurityFilterChain instances, each configured with a specific set of filters tailored to particular URL patterns or security requirements.[4]
The default filter chain, when using standard HttpSecurity configuration, includes a predefined sequence of filters such as SecurityContextPersistenceFilter for establishing the security context, HeaderWriterFilter for security headers, CsrfFilter for cross-site request forgery protection, UsernamePasswordAuthenticationFilter for form-based authentication, ExceptionTranslationFilter for handling security exceptions, and AuthorizationFilter for access control decisions. This chain begins with early filters like ChannelProcessingFilter, which enforces secure (HTTPS) or insecure (HTTP) channel requirements based on configuration, followed by context setup and authentication filters before authorization and exception handling. The ordering is strictly enforced to respect dependencies, such as performing authentication prior to authorization; deviations can lead to security vulnerabilities. Custom filters can be inserted using methods like addFilterBefore, addFilterAfter, or addFilterAt on HttpSecurity, allowing precise placement relative to existing filters.[4]
During request processing, each filter in the chain examines the HttpServletRequest and may modify it, invoke the next filter via chain.doFilter(), or short-circuit the chain by directly writing to the HttpServletResponse—for instance, redirecting unauthenticated users to a login page or rejecting invalid CSRF tokens. The FilterChainProxy selects the appropriate SecurityFilterChain using a RequestMatcher, ensuring only relevant filters are applied; if no match is found, the request proceeds unsecured unless a default chain catches it. This modular design, configured via HttpSecurity for web-specific setups, enables zoned security where different paths (e.g., public APIs vs. admin areas) use distinct chains.[4]
A significant evolution occurred in version 3.1, introducing support for multiple SecurityFilterChain instances within a single FilterChainProxy, configurable via multiple <http> elements in XML or equivalent Java configuration. This allows defining separate chains for different request patterns, such as stateless authentication for REST endpoints and form-based login for web UIs, with the first matching chain taking precedence. For non-blocking applications built with Spring WebFlux, Spring Security 5.0+ provides reactive support through WebFilterChain, which processes requests asynchronously using reactive streams, adapting the filter mechanics to handle backpressure and non-blocking I/O without servlet dependencies.[20][21]
Authentication
Authentication Mechanisms
Spring Security offers a variety of built-in authentication mechanisms to verify user identities, ranging from traditional username/password-based approaches to certificate and token-based methods. These mechanisms integrate with the framework's core authentication architecture, allowing developers to configure authentication flows that suit different application requirements, such as web applications, REST APIs, or enterprise environments.[22]
Built-in Authentication Providers
The framework includes several pre-configured AuthenticationProvider implementations that handle specific authentication scenarios. The DaoAuthenticationProvider is a key provider for database-backed authentication, relying on a UserDetailsService to load user details and a PasswordEncoder to validate credentials against stored hashed passwords. It processes UsernamePasswordAuthenticationToken objects, retrieving the UserDetails for the provided username and comparing the submitted password using the encoder, enabling seamless integration with relational databases or other data sources via custom UserDetailsService implementations.[23]
For directory services, the LdapAuthenticationProvider facilitates authentication against LDAP servers, including Active Directory, without requiring a traditional UserDetailsService since LDAP bind operations do not expose passwords. It supports bind authentication, where user credentials are used directly to bind to the LDAP directory, and password comparison modes for verifying hashed values, often combined with an LdapAuthoritiesPopulator to map directory attributes to Spring Security authorities. This provider is particularly useful in enterprise settings for centralizing user management.[24]
The RememberMeAuthenticationProvider supports persistent login functionality, processing RememberMeAuthenticationToken instances generated from secure cookies or tokens stored on the client side. It requires a shared key for token validation and a UserDetailsService to reconstruct the user's authentication details upon presentation of a valid remember-me token, allowing users to remain authenticated across sessions without re-entering credentials. This provider enhances user experience while maintaining security through token expiration and hashing.[25]
Authentication Mechanisms
Spring Security supports form-based login as a standard web authentication method, where users submit credentials via an HTML form, typically handled by the UsernamePasswordAuthenticationFilter. Upon submission, the filter creates an authentication token and delegates to the AuthenticationManager; successful authentication triggers session creation and redirection, while failures redirect to an error page, with customizable login pages and CSRF protection enabled by default.[26]
HTTP Basic authentication provides a simple, stateless mechanism for API access, sending credentials in the Authorization header as base64-encoded username:password pairs per RFC 7617. The BasicAuthenticationFilter extracts and validates these credentials, prompting clients with a WWW-Authenticate challenge on unauthorized requests, making it suitable for non-browser clients like mobile apps or scripts, though it requires HTTPS to mitigate eavesdropping risks.[27]
Digest authentication addresses Basic's clear-text vulnerabilities by using a challenge-response protocol based on RFC 2617, where the server issues a nonce and the client responds with a hashed digest of credentials and request details. Implemented via DigestAuthenticationFilter, it supports MD5 or plaintext password storage but is deprecated for new applications due to weaker hashing compared to modern adaptive algorithms, recommending migration to token-based alternatives.[28]
X.509 certificate authentication leverages client certificates for mutual TLS (mTLS) verification, extracting the subject's distinguished name from the presented certificate to identify the user. The X509AuthenticationFilter maps the certificate details to a principal using regex patterns on the subject DN, integrating with a UserDetailsService for authority loading, ideal for environments requiring strong, non-interactive identity proof like internal networks or IoT devices.[29]
Since version 5.2, Spring Security has provided native support for JWT bearer tokens as part of its OAuth 2.0 Resource Server features, validating self-contained JSON Web Tokens via a JwtDecoder that checks signatures, expiration, and claims against a configured issuer. This enables stateless authentication for microservices and APIs, with scopes mapped to authorities, using libraries like Nimbus JOSE + JWT for decoding and verification.[30]
Extensibility
Developers can extend authentication by implementing the AuthenticationProvider interface, which defines methods to support custom Authentication tokens and perform bespoke verification logic, such as integrating with external identity providers or proprietary protocols. Instances are registered with the ProviderManager to participate in the authentication chain, allowing fallback to other providers if unsupported, thus supporting hybrid or multi-provider setups.[17]
Post-authentication behavior is customizable through handlers like AuthenticationSuccessHandler and AuthenticationFailureHandler, invoked after successful or failed attempts to manage redirects, session adjustments, or additional checks. For instance, the success handler can redirect to a landing page or trigger auditing, while the failure handler logs attempts or enforces lockouts, providing hooks for tailored user experiences without altering core provider logic.[17]
Specific Features
Password encoding is handled by the BCryptPasswordEncoder, which became the default under the DelegatingPasswordEncoder in Spring Security 5.0, applying the bcrypt algorithm with adaptive work factors (default strength of 10) to resist brute-force attacks by slowing verification to approximately one second per password. This shift from the insecure NoOpPasswordEncoder ensures hashed storage for all new credentials, with legacy support via prefixed encodings.[31]
As of Spring Security 7.0 (released November 2025), the framework provides native support for multi-factor authentication (MFA) through declarative configuration, enabling requirements for multiple authentication factors such as passwords and one-time tokens (OTT). This is achieved using annotations like @EnableMultiFactorAuthentication and factor-specific authorities (e.g., PASSWORD_AUTHORITY, OTT_AUTHORITY) in authorization rules, with options for global or selective enforcement on specific endpoints. Custom AuthenticationProvider implementations remain available for advanced or legacy multi-step flows, such as integrating TOTP or hardware tokens via provider chaining.[32][17]
Authentication Process Flow
The authentication process in Spring Security begins when an incoming HTTP request enters the security filter chain, where it is intercepted by one or more authentication filters configured for the application, such as UsernamePasswordAuthenticationFilter for form-based login or BasicAuthenticationFilter for HTTP Basic authentication. These filters extract the principal and credentials from the request—typically a username and password submitted via a form or headers—and encapsulate them into a pre-authenticated Authentication object, such as UsernamePasswordAuthenticationToken. This object is then submitted to the central AuthenticationManager for verification.[17]
The AuthenticationManager, usually implemented as a ProviderManager, delegates the authentication attempt to a chain of AuthenticationProvider instances, each responsible for a specific mechanism; for example, DaoAuthenticationProvider loads user details via a UserDetailsService implementation and validates the credentials against stored data, such as hashed passwords from a database. If a provider successfully authenticates the token—confirming the credentials match the loaded UserDetails—it returns a fully populated Authentication object with authorities and principal details; otherwise, it throws an exception, and the manager proceeds to the next provider until exhaustion or success. Upon successful authentication, the Authentication is stored in the SecurityContextHolder (typically using a ThreadLocal strategy for the current request thread), making the authenticated user's identity available throughout the application. Additionally, Spring Security invokes session management strategies, including protection against session fixation attacks by invalidating the existing session (if any) and creating a new one, migrating necessary attributes to prevent session hijacking.[17][17][33]
For unauthenticated requests that do not trigger explicit authentication attempts, Spring Security automatically applies anonymous authentication by setting an AnonymousAuthenticationToken in the SecurityContextHolder, assigning a default anonymous user with limited authorities to allow graceful handling of public resources without full authentication. On authentication success, an AuthenticationSuccessHandler is invoked, which by default redirects the user to a configured success URL or forwards the request; the process also clears sensitive credentials from the Authentication object for security and publishes an authentication success event. In contrast, failure triggers an AuthenticationException, handled by an AuthenticationFailureHandler that delegates to an AuthenticationEntryPoint—such as LoginUrlAuthenticationEntryPoint for form login, which redirects to a login page, or a simple response sender for APIs resulting in an HTTP 401 Unauthorized status. Forbidden access (post-authentication but lacking permissions) may yield HTTP 403, though this is configurable via exception translation in the filter chain.[34][17][17]
This core authentication flow has been a foundational element since the early versions of Spring Security, evolving from its Acegi Security origins to support modern requirements. With the release of Spring Security 5.0 in 2018, enhancements introduced reactive authentication flows compatible with Spring WebFlux, using non-blocking operators like Mono<Authentication> for handling credentials and providers in asynchronous environments. For stateless authentication in RESTful APIs, applications can configure session creation policies to avoid HTTP session usage altogether—relying instead on token-based mechanisms like JWT—ensuring scalability without server-side state.[17][35][33]
Authorization
Access Control Strategies
Spring Security employs URL and resource-based authorization to enforce access control at the web layer, ensuring that only authenticated and authorized users can interact with protected endpoints. This approach originated in the Acegi Security System for Spring, which began development in late 2003 and introduced foundational access control mechanisms that evolved into modern Spring Security features. The core strategy revolves around pattern matching for URLs, using Ant-style syntax to define rules for paths, such as requiring the ROLE_ADMIN authority for all requests under /admin/**. This allows developers to specify granular permissions, where wildcards like * match single path segments and ** match multiple segments, enabling broad yet precise coverage of resource hierarchies.[36] Additionally, HTTP method restrictions can be layered on these patterns, for instance, permitting anonymous GET requests to /public/** while mandating authentication for POST operations on the same paths.[36]
Configuration of these strategies occurs primarily through the HttpSecurity.authorizeHttpRequests() method, which defines a chain of authorization rules evaluated in order against incoming requests. Role-based access uses hasRole("ADMIN") to check for prefixed authorities like ROLE_ADMIN, whereas authority-based access employs hasAuthority("ADMIN") for unprefixed permissions, allowing for more flexible, custom granular controls without the automatic ROLE_ prefix.[36][19] For example, the following lambda-style configuration permits public access to static resources, restricts administrative paths to admins, and denies all other requests:
java
http.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/static/**").permitAll()
.requestMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().denyAll());
http.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/static/**").permitAll()
.requestMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().denyAll());
This DSL style, introduced in Spring Security 5.2, enhances readability by leveraging lambdas and eliminating the need for explicit .and() chaining between rules.[37]
Key features augment these strategies for enhanced security. Explicit matchers like permitAll() allow unrestricted access to public endpoints, denyAll() blocks all traffic to sensitive paths, and IP-based restrictions via hasIpAddress("192.168.1.1") in SpEL expressions (e.g., .access("hasIpAddress('192.168.1.1')")) provide network-level filtering for added defense in depth.[36] These elements collectively form a robust framework for URL-level authorization, balancing accessibility with protection. CSRF protection and channel security are configured separately and covered in advanced features.[38]
Method and Instance Security
Spring Security provides fine-grained security at the method and instance levels through annotation-driven mechanisms integrated with Aspect-Oriented Programming (AOP). This approach allows developers to enforce authorization rules directly on business logic methods and domain objects, complementing URL-based access controls by targeting code-level invocations. From its origins, Spring Security has leveraged Spring AOP to intercept method calls, enabling declarative security without invasive changes to application code.[39]
To enable method security, developers configure @EnableMethodSecurity (replacing the deprecated @EnableGlobalMethodSecurity in Spring Security 5.6 and later) on a Spring @Configuration class, which activates proxy-based interception using Spring AOP. This setup registers interceptors like AuthorizationManagerBeforeMethodInterceptor for pre-method checks and supports both JDK dynamic proxies and CGLIB for class-based proxies, ensuring security applies to public methods in Spring-managed beans. For domain object security, the framework extends this to instance-level protections, such as filtering collections or validating return objects post-invocation.[39][40]
Annotation-based security includes @PreAuthorize for evaluating expressions before method execution, preventing unauthorized access; for example, @PreAuthorize("hasRole('ADMIN')") restricts a method to users with the ADMIN role using Spring Expression Language (SpEL). Similarly, @PostAuthorize performs checks after execution, often on return values, such as @PostAuthorize("returnObject.owner == authentication.name") to ensure users access only their own data. The @Secured annotation offers a simpler role-based alternative, like @Secured("ROLE_ADMIN"), but requires explicit enabling via securedEnabled = true in configuration. Spring Security also supports JSR-250 standard annotations, including @RolesAllowed("ROLE_USER") for role checks, @PermitAll for unrestricted access, and @DenyAll for blocking all invocations, activated with jsr250Enabled = true. SpEL expressions in these annotations provide dynamic evaluation, accessing context like authentication.principal or custom methods for complex logic.[39]
Instance-level features focus on securing domain objects through after-invocation mechanisms. @PostFilter filters return collections based on SpEL, e.g., @PostFilter("filterObject.owner == [authentication](/page/Authentication).name") returns only user-owned items, while @PreFilter applies similar logic to input parameters. For broader domain security, @EnableMethodSecurity with object-return authorization uses proxies to wrap returned instances, enforcing rules like ownership via AuthorizationProxyFactory. These post-invocation checks integrate seamlessly with AOP, allowing data filtering without altering core business methods.[39]
Spring Security extends method security to reactive applications using WebFlux (since 5.2), enabled via @EnableReactiveMethodSecurity. This leverages Reactor's Context and ReactiveSecurityContextHolder to propagate authentication in non-blocking flows, supporting the same annotations on methods returning Publisher types like Mono or Flux; for instance, @PreAuthorize("hasRole('USER')") public Mono<Account> readAccount(Long id);. Key improvements include native AOP support, Kotlin coroutine compatibility, and the AuthorizationManager API for streamlined custom rules (enhanced in 6.x), differing from servlet-based security by handling asynchronous streams without blocking.[40]
Advanced Features
Protection Against Common Attacks
Spring Security incorporates several mechanisms to defend against prevalent web vulnerabilities, primarily through its security filter chain and HTTP response headers. These protections target threats such as Cross-Site Request Forgery (CSRF), session-related exploits, and clickjacking, ensuring robust defense for Spring-based applications without requiring extensive custom implementation.[2]
CSRF Protection
CSRF attacks are mitigated in Spring Security via the synchronizer token pattern, enforced by the CsrfFilter which generates and validates a unique token for each user session.[38] This filter ensures that non-safe HTTP methods, like POST and PUT, include the token—either as a hidden form field automatically inserted by Spring's form tags or as a custom header for AJAX requests—to verify the request's legitimacy.[38] For stateless RESTful APIs, where sessions are not used, CSRF protection can be explicitly disabled via configuration to avoid token overhead, such as using .csrf(csrf -> csrf.disable()) in HttpSecurity.[38] This token-based approach has been enabled by default since Spring Security 3.2, providing out-of-the-box safeguards for traditional web applications.[38]
Session Management
Spring Security's session management features prevent unauthorized access and reuse of sessions, including controls for concurrency, fixation attacks, and secure cookie handling. Concurrent session control limits the number of simultaneous sessions per user—configured via maximumSessions(n) in SessionManagementConfigurer—and can either expire the oldest session or block new authentications when the limit is reached, requiring a HttpSessionEventPublisher for event tracking.[33] On logout, the framework automatically invalidates the HTTP session using SecurityContextLogoutHandler, clearing the security context and removing the session cookie to prevent post-logout access.[41]
Session fixation attacks, where an attacker forces a victim's session ID, are countered by generating a new session ID post-authentication; since version 4.0, this leverages HttpServletRequest.changeSessionId() (available in Servlet 3.1) as the default strategy, with alternatives like migrateSession for older environments.[33] To enhance cookie security, Spring Security sets the HttpOnly flag—introduced in version 3.1 for Servlet 3.0 containers—to block JavaScript access to session cookies, and the Secure flag to restrict transmission to HTTPS-only connections, configurable via sessionManagement().sessionCreationPolicy().[20][33]
Additional Attack Mitigations
Clickjacking, which tricks users into unintended actions via framed content, is prevented by default through the X-Frame-Options: DENY header, set by Spring Security's FrameOptionsConfig, blocking the application's pages from being embedded in iframes.[42] Since version 4.1, developers can configure advanced security headers for broader protection: HTTP Strict Transport Security (HSTS) enforces HTTPS with defaults like max-age=31536000; includeSubDomains, mitigating man-in-the-middle attacks, while Content Security Policy (CSP) restricts resource loading (e.g., script-src 'self') to counter cross-site scripting (XSS).[42] These headers, managed via HttpSecurity.headers(), align with OWASP Top 10 risks such as injection (A1:2017 via CSP) and security misconfiguration (A6:2017 via HSTS), promoting comprehensive vulnerability mitigation.[42]
Integration with Modern Protocols
Spring Security offers robust integration with OAuth 2.0 and its evolving successor, OAuth 2.1, enabling applications to act as both resource servers and clients in secure authorization flows. As a resource server, it validates access tokens, supporting both JWT and opaque token formats through dependencies like spring-boot-starter-oauth2-resource-server. JWT decoding is handled via the Nimbus JOSE + JWT library, utilizing NimbusJwtDecoder for signature verification against issuer metadata or public keys. Client-side support, provided by spring-boot-starter-oauth2-client, facilitates grants such as authorization code and client credentials, with configurable ClientRegistration for endpoints and scopes. From version 6.0 onward, Spring Security establishes a baseline compliance with OAuth 2.1 draft specifications, incorporating best practices like exact redirect URI matching and deprecation of insecure flows. In version 7.0, support for the deprecated resource owner password credentials grant was removed to further align with OAuth 2.1 security recommendations. Additionally, version 7.0 introduces support for Demonstrating Proof-of-Possession (DPoP)-bound access tokens, which bind tokens to a client's public key proof to prevent token theft and replay attacks.[43][44][45]
For public clients, Proof Key for Code Exchange (PKCE) is mandatory starting in Spring Security 6.1, enhancing security against authorization code interception by requiring dynamic code challenges in the authorization code grant flow. This aligns with OAuth 2.0 extensions for native and single-page applications, where clients without secrets generate a code verifier and challenge to bind requests. Reactive applications benefit from OAuth filters introduced in version 5.0, using WebClient with ExchangeFilterFunction for non-blocking token propagation and validation in WebFlux environments.[46]
OpenID Connect (OIDC) integration builds on OAuth 2.0 foundations, providing identity layer features for user authentication. Spring Security validates ID tokens issued by OIDC providers, extracting claims like subject and audience during the authorization code flow. Since version 5.2, it supports OIDC discovery endpoints, allowing automatic configuration of ClientRegistration from the provider's .well-known/openid-[configuration](/page/Configuration) metadata, which includes authorization, token, and userInfo endpoints. This streamlines setup for providers like Google or Keycloak, ensuring issuer verification and token introspection without manual endpoint specification.[47][48]
SAML 2.0 support enables web single sign-on (SSO) through core framework components, replacing the deprecated Spring SAML extension. The extension, previously handling SAML authentication and federation, was moved into Spring Security's core starting in version 5.2, with full migration guidance for 6.x applications emphasizing RelyingPartyRegistration for service provider configuration. This includes support for authentication requests, assertion validation, and logout flows using OpenSAML libraries, ensuring compatibility with identity providers like Okta. In version 6.x, deprecated extension artifacts like spring-security-saml2-[core](/page/Core) are no longer maintained, directing users to core modules such as spring-security-saml2-service-provider for metadata generation and binding.[49][50]
Configuration and Integration
Basic Setup Approaches
Spring Security offers several foundational approaches to configure security in Java-based web applications, primarily through Java-based configuration and auto-configuration in Spring Boot. The core mechanism involves annotating a configuration class with @EnableWebSecurity, which activates Spring Security's web security support and integrates it with Spring MVC by registering the springSecurityFilterChain servlet filter.[51] This annotation enables the definition of security rules via beans, such as SecurityFilterChain, which customize HTTP security behaviors like authentication and authorization.[51]
Historically, annotation-driven configuration relied on extending the WebSecurityConfigurerAdapter class to override methods like configure(HttpSecurity http), providing a straightforward way to set up authentication and access controls. However, this approach was deprecated in Spring Security 5.7.0-M2 to promote a more modular, component-based configuration model.[52] In Spring Security 6.0, the recommended replacement is the lambda Domain-Specific Language (DSL), which allows concise configuration of SecurityFilterChain beans using lambda expressions for better readability and flexibility.[53] For instance, a basic lambda DSL setup might look like this:
java
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authz -> authz
.requestMatchers("/public/**").permitAll()
.anyRequest().authenticated()
)
.formLogin(withDefaults());
return http.build();
}
}
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authz -> authz
.requestMatchers("/public/**").permitAll()
.anyRequest().authenticated()
)
.formLogin(withDefaults());
return http.build();
}
}
This example permits access to public endpoints while requiring authentication for others, enabling form-based login by default.[51]
For testing and prototyping, Spring Security supports in-memory user storage through the InMemoryUserDetailsManager, which allows defining users and roles directly in code without a database. A simple implementation involves creating a UserDetailsService bean:
java
@Bean
public [UserDetailsService](/page/User) userDetailsService() {
[UserDetails](/page/User) user = [User](/page/User).withDefaultPasswordEncoder()
.username("[user](/page/User)")
.password("[password](/page/Password)")
.roles("[USER](/page/User)")
.build();
return new InMemoryUserDetailsManager([user](/page/User));
}
@Bean
public [UserDetailsService](/page/User) userDetailsService() {
[UserDetails](/page/User) user = [User](/page/User).withDefaultPasswordEncoder()
.username("[user](/page/User)")
.password("[password](/page/Password)")
.roles("[USER](/page/User)")
.build();
return new InMemoryUserDetailsManager([user](/page/User));
}
This setup uses a default password encoder suitable only for development, as production environments require stronger hashing.[51] For persistent storage, JDBC authentication integrates with relational databases using a DataSource and predefined SQL queries to retrieve user credentials and authorities. Spring Security provides default queries, such as SELECT username, password, enabled FROM users WHERE username = ? for authentication, assuming a schema with users and authorities tables.[54] Configuration involves a JdbcDaoAuthProvider bean wired to the DataSource, enabling database-backed user management.[54]
In Spring Boot applications, bootstrapping Spring Security is streamlined via the spring-boot-starter-security dependency, which triggers auto-configuration to secure all HTTP endpoints with HTTP Basic authentication by default upon classpath detection.[55] This minimal setup generates a random password for the default "user" account, logged at startup, and protects resources while allowing form login customization if needed.[55] Since Spring Security 5.0, password encoding has migrated to the DelegatingPasswordEncoder, a composite encoder that prefixes encoded passwords with an identifier (e.g., {[bcrypt](/page/Bcrypt)}) to support multiple algorithms and facilitate upgrades without re-encoding existing data.[31] Additionally, CSRF protection is enabled by default for browser-based clients but should be disabled for non-browser API consumers, as these are not vulnerable to cross-site request forgery attacks.[56] A basic configuration thus yields both form login and Basic authentication out of the box, providing immediate security for web applications.[55]
Extensions with Spring Ecosystem
Spring Security seamlessly integrates with Spring Boot through auto-configuration mechanisms that simplify securing applications, particularly for OAuth2 and actuator endpoints. When Spring Security is on the classpath, Spring Boot automatically secures web applications, including the /error endpoint, and provides a default user with username "user" and a random password logged at startup.[57] Developers can customize this via properties such as spring.security.user.name=admin and spring.security.user.password=secret.[57] For OAuth2, auto-configuration activates with dependencies like spring-security-oauth2-client, enabling client registrations via properties (e.g., spring.security.oauth2.client.registration.my-client.client-id=abcd and spring.security.oauth2.client.registration.my-client.client-secret=password), supporting both OAuth2 and OpenID Connect with issuer URIs.[57] Actuator endpoints are secured by default; customization uses EndpointRequest to define access rules based on paths like management.endpoints.web.base-path.[57] As of Spring Boot 3.x (aligned with Spring Framework 6.x), it requires Spring Security 6.x to align with Jakarta EE 10 and Spring Framework 6.0 baselines. Starting with Spring Boot 4.0 (November 2025), it requires Spring Security 7.0 to align with Jakarta EE 11 and Spring Framework 7.0 baselines.[58][59]
In reactive environments, Spring Security provides non-blocking authentication support via Spring WebFlux, introduced in version 5.0 released on November 28, 2017.[12] The SecurityWebFilterChain serves as the core configuration for reactive web security, analogous to HttpSecurity in servlet stacks but optimized for asynchronous processing.[21] This enables event-driven security filters that handle authentication without blocking threads, integrating with reactive streams for scalable applications.[21]
Spring Security extends to other Spring projects for specialized use cases. With Spring Cloud, it integrates via Spring Cloud Gateway using filters like TokenRelay to propagate OAuth2 access tokens downstream, requiring spring-boot-starter-oauth2-client and configuration in YAML or Java DSL (e.g., filters: - TokenRelay=).[60] The SaveSession filter ensures security details persist with Spring Session.[60] For data access, integration with Spring Data JPA allows security-aware queries through the spring-security-data module; a SecurityEvaluationContextExtension bean enables expressions like @Query("select m from Message m where m.to.id = ?#{ principal?.id }") to reference the authenticated principal.[61] In GraphQL applications, Spring Security secures endpoints via HTTP URL patterns and fine-grained annotations like @PreAuthorize on resolvers, with context propagation for authenticated access control in both MVC and WebFlux setups.[62] Version 6.5 enhances cloud-native observability with automatic Micrometer context propagation, supporting distributed tracing in service mesh environments. As of November 17, 2025, Spring Security 7.0.0 was released, featuring modular configuration for Servlet and WebFlux, enhanced OAuth 2.0 support (including PKCE enabled by default and HTTP service clients), new password encoders like Argon2, and removal of deprecated features for alignment with Spring Framework 7.0.[45][15]