Back to blog

// OSSeva Blog

Migration

Spring Security 5.8 to 6.x Migration: What Breaks and How to Prepare on 5.8

Matt Reynolds7 min read

The short answer

Do most of the work on 5.8. The Spring Security team designed 5.8 so that nearly every default that changes in 6.0 can be switched on early, with the deprecated APIs still present and Spring Boot 2.7 underneath. Its migration guide, "Preparing for 6.0", lists each change with the 5.8 configuration that opts into it. Apply them one at a time, test each one, and the move to 6.x comes down to removing deprecated calls and doing the Spring Boot 3 upgrade.

Check the dates before you pick a target. Open source support for 5.8 ended on 31 December 2023. Every 6.x line is now out of open source support too: 6.5, the last of them, ended on 30 June 2026. The lines with open source support are 7.0, until 31 December 2026, and 7.1, until 31 July 2027. So 6.x is a waypoint. Spring's documentation describes 6.5 as the bridge to 7.0, the way 5.8 was the bridge to 6.0.

What changes in 6.0

All of these come from the 5.8 migration guide.

AreaChange in 6.0Prepare on 5.8 by
ConfigurationWebSecurityConfigurerAdapter removedPublishing SecurityFilterChain, WebSecurityCustomizer and AuthenticationManager beans
ConfigurationantMatchers, mvcMatchers and regexMatchers removedSwitching to requestMatchers, which picks MvcRequestMatcher when Spring MVC is on the classpath and AntPathRequestMatcher otherwise
Configuration@Configuration removed from @EnableWebSecurity, @EnableMethodSecurity and related annotationsAdding @Configuration to those classes
Request authorizationauthorizeHttpRequests and AuthorizationManager replace authorizeRequests and AccessDecisionManagerMoving to authorizeHttpRequests and replacing custom voters
Request authorizationRequests with no matching rule are deniedEnding every rule set with an explicit anyRequest() rule
Request authorizationAll dispatcher types are authorized, including FORWARD, INCLUDE and ERRORTesting forwards and error pages, and permitting them where needed
Request authorizationhasRole in authorizeHttpRequests ignores a custom GrantedAuthorityDefaults prefixUsing hasAuthority with the full authority name
Method security@EnableGlobalMethodSecurity deprecated (not removed)Switching to @EnableMethodSecurity, which enables pre and post annotations by default
CSRFLoading of the CsrfToken is deferred until neededOpting into deferred loading with CsrfTokenRequestAttributeHandler
CSRFBREACH protection: the token is masked with XorCsrfTokenRequestAttributeHandlerOpting in, and fixing single-page apps that read the token from a cookie
SessionsThe SecurityContext is no longer saved automatically; SecurityContextHolderFilter only reads itSetting requireExplicitSave(true) and saving the context in custom authentication code
SessionsDefault repository becomes DelegatingSecurityContextRepository; the RequestCache is only checked when a continue parameter is present; authentication mechanisms must call the SessionAuthenticationStrategy themselvesApplying each opt-in from the guide
AuthenticationRemember-me tokens use SHA-256; AuthenticationServiceException goes to the container instead of the entry pointEncoding with SHA-256 while still matching MD5, and rethrowing service exceptions
PasswordsNew minimums for PBKDF2, SCrypt and Argon2 encodersReplacing deprecated encoder constructors; no action if you use the default encoder
OAuth2oauth2Login() grants OAUTH2_USER or OIDC_USER instead of ROLE_USERUpdating rules that check hasRole("USER") for OAuth2 users
OAuth2Implicit grant support and deprecated OAuth2 client classes removed; JwtAuthenticationConverter#extractAuthorities removedUsing the listed replacements and setJwtGrantedAuthoritiesConverter
SAMLOpenSAML 4 and OpenSaml4AuthenticationProviderUpgrading OpenSAML and the provider on 5.8

The order to do it in

  1. Get onto the latest patch releases of Spring Boot 2.7 and Spring Security 5.8. On Boot 2.7 this means overriding the Spring Security version from 5.7 to 5.8, which the guide notes is fully compatible.
  2. Turn on deprecation warnings in the build and treat them as the work list.
  3. Remove WebSecurityConfigurerAdapter and the old matchers. These are compile-time changes with no behaviour change on 5.8, so they are the safest place to start.
  4. Switch to authorizeHttpRequests, add an explicit anyRequest() rule, then turn on filtering of all dispatcher types.
  5. Apply the CSRF, session, authentication and OAuth2 opt-ins one at a time, each in its own release, with the tests below run for each.
  6. Upgrade to Spring Boot 3 and Spring Security 6. This brings Java 17 and the move from javax.* to jakarta.*; see the Spring Boot 2 to 3 migration guide.
  7. Continue to 6.5, then follow its "Preparing for 7.0" steps before moving to Spring Security 7 on Spring Boot 4.

Before and after

A typical 5.x configuration:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/admin/**").hasRole("ADMIN")
                .antMatchers("/public/**").permitAll()
                .anyRequest().authenticated()
            .and()
            .formLogin();
    }
}

The same rules written so they compile on 5.8 and on 6.x:

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests((authz) -> authz
                .requestMatchers("/admin/**").hasRole("ADMIN")
                .requestMatchers("/public/**").permitAll()
                .anyRequest().authenticated()
            )
            .formLogin(Customizer.withDefaults());
        return http.build();
    }
}

If a single-page application breaks after the CSRF changes and you need time to fix it, the guide gives an opt-out that restores the 5.8 behaviour:

CsrfTokenRequestAttributeHandler requestHandler = new CsrfTokenRequestAttributeHandler();
requestHandler.setCsrfRequestAttributeName(null);
http.csrf((csrf) -> csrf.csrfTokenRequestHandler(requestHandler));

Use opt-outs as temporary measures with a ticket attached, not as the end state.

Test plan

Most of these changes fail open or fail closed without a compile error, so the tests have to check behaviour.

  • Build an access matrix before you change anything. List every endpoint with the expected status for an anonymous user and for each role, and write it as a table-driven MockMvc or WebTestClient test using spring-security-test. Run it on the current version first, so you know it passes, then after every step.
  • Look for new 403 responses after deny-by-default and dispatcher filtering, especially on error pages, forwards to views and endpoints that previously had no rule.
  • Log in, then make a second request. A login that appears to work but leaves the user anonymous on the next request is the usual symptom of the explicit-save change in custom authentication filters.
  • Test CSRF from real clients: server-rendered forms, single-page apps that read the token from a cookie, and any client that sends the token in a header.
  • Test every authentication route: form login, HTTP Basic, remember-me cookies issued before the change, OAuth2 and OIDC login with the new authorities, JWT resource servers and SAML.
  • Check method security still applies after moving to @EnableMethodSecurity, including any custom expression handler or permission evaluator.
  • Include actuator and management endpoints in the access matrix. They are easy to forget and often the most sensitive.

Rollback

Each preparation step on 5.8 is a code or configuration change, so it rolls back with a redeploy of the previous build. That is the main benefit of doing the work on 5.8. Two things persist and need checking before each rollout:

  • Stored credentials and tokens. Password hashes written with new encoder settings and remember-me cookies issued with SHA-256 must still be readable by the version you might roll back to. The guide's remember-me opt-in encodes with SHA-256 while still matching MD5 for this reason.
  • Sessions. A serialized SecurityContext in a shared session store, such as Spring Session on Redis or JDBC, may not deserialize across Spring Security versions. Plan to invalidate sessions when you cut over and when you roll back.

The Spring Boot 3 step itself is a larger change. Keep the last Boot 2.7 build deployable, with its own patched dependencies, until the new version has run through a full release cycle.

If the migration will take longer than your support window

Commercial support from Broadcom covers 5.8 until 30 June 2029 and 6.5 until 30 June 2032, under a Spring enterprise subscription. OSSeva is the other route. It ships patched Spring Security builds for 5.6, 5.7 and 5.8 and for the 6.0 to 6.5 lines that have left open source support, with emergency patches for authentication bypass CVEs, delivered as signed artifacts through Maven Central or your private repository. Assure adds a Spring Security configuration audit, an OAuth 2.0 and OIDC review, a Spring Security 6 migration assessment, VEX attestation for scanner findings and SOC 2 or PCI DSS evidence. Operate adds 24/7 monitoring of authentication events, a 15-minute P1 response for authentication bypass incidents and execution of the Spring Security 6 migration. See Spring Security support and Spring continuation.

Related

Tags

Spring SecuritySpring BootMigrationSpring Security 6Java

Ready to get your open source under control?

Talk to an OSSeva engineer about CVE coverage, compliance, and migration support for your stack.