eBook – Guide Spring Cloud – NPI EA (cat=Spring Cloud)
announcement - icon

Let's get started with a Microservice Architecture with Spring Cloud:

>> Join Pro and download the eBook

eBook – Mockito – NPI EA (tag = Mockito)
announcement - icon

Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.

Get started with mocking and improve your application tests using our Mockito guide:

Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Reactive – NPI EA (cat=Reactive)
announcement - icon

Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:

>> Join Pro and download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Jackson – NPI EA (cat=Jackson)
announcement - icon

Do JSON right with Jackson

Download the E-book

eBook – HTTP Client – NPI EA (cat=Http Client-Side)
announcement - icon

Get the most out of the Apache HTTP Client

Download the E-book

eBook – Maven – NPI EA (cat = Maven)
announcement - icon

Get Started with Apache Maven:

Download the E-book

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

eBook – RwS – NPI EA (cat=Spring MVC)
announcement - icon

Building a REST API with Spring?

Download the E-book

Course – LS – NPI EA (cat=Jackson)
announcement - icon

Get started with Spring and Spring Boot, through the Learn Spring course:

>> LEARN SPRING
Course – RWSB – NPI EA (cat=REST)
announcement - icon

Explore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:

>> The New “REST With Spring Boot”

Course – LSS – NPI EA (cat=Spring Security)
announcement - icon

Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.

I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.

You can explore the course here:

>> Learn Spring Security

Course – LSD – NPI EA (tag=Spring Data JPA)
announcement - icon

Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.

Get started with Spring Data JPA through the guided reference course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (cat=Spring Boot)
announcement - icon

Refactor Java code safely — and automatically — with OpenRewrite.

Refactoring big codebases by hand is slow, risky, and easy to put off. That’s where OpenRewrite comes in. The open-source framework for large-scale, automated code transformations helps teams modernize safely and consistently.

Each month, the creators and maintainers of OpenRewrite at Moderne run live, hands-on training sessions — one for newcomers and one for experienced users. You’ll see how recipes work, how to apply them across projects, and how to modernize code with confidence.

Join the next session, bring your questions, and learn how to automate the kind of work that usually eats your sprint time.

Course – Summer Sale 2026 – NPI EA (cat= Baeldung)
announcement - icon

Yes, we're now running our only Summer Sale. All Courses are 30% off until 20th July, 2026:

>> EXPLORE ACCESS NOW

Course – Summer Sale 2026 – NPI (cat=Baeldung)
announcement - icon

Yes, we're now running our only Summer Sale. All Courses are 30% off until 20th July, 2026:

>> EXPLORE ACCESS NOW

1. Overview

Authentication is the first line of defense in all web applications. Traditionally, applications rely on a username and password to verify a user’s identity. However, experts no longer consider relying on a single authentication factor secure for modern systems.

Multi-Factor Authentication (MFA) addresses this by requiring users to verify their identity using multiple independent factors before accessing a system.

Spring Security 7 introduces built-in support for multi-factor authentication, allowing developers to enforce multiple authentication steps using the existing authorization model. In this article, we’ll explore how MFA works in Spring Security 7 and how to implement it in a Spring Boot application.

2. Understanding MFA in Spring Security 7

Spring Security 7 introduces a new way to model authentication factors using authorities. Instead of treating MFA as a separate authentication mechanism, Spring Security progressively grants authorities for each successful authentication factor.

Multi-Factor Authentication (MFA) strengthens security by requiring users to verify their identity using multiple independent factors. These factors typically fall into three categories: something the user knows, such as a password or PIN, something the user has, such as a mobile device or email token, and something the user is, such as a fingerprint or other biometric data. By combining these factors, applications significantly reduce the risk of compromised credentials and unauthorized access.

Each time a user successfully authenticates with a specific factor, Spring Security adds a corresponding authority to the authentication object. This authority represents the factor that has already been verified during the authentication process. Some common examples include FACTOR_PASSWORD for password-based authentication, FACTOR_X509 for certificate-based authentication, and FACTOR_OTT for one-time token authentication. These authorities are represented internally by the FactorGrantedAuthority class and become part of the authenticated user’s security context.

This design allows authorization rules to verify that the required authentication factors are satisfied before granting access to protected resources.

3. Project Setup

Before implementing multi-factor authentication, we’ll set up a simple Spring Boot application using Spring Initializr with Spring Security 7. First, we need to configure the required dependencies.

We include Spring Boot starters for web, security, starter-test, webmvc-test, and security-testing:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>4.0.3</version>
</dependency>

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

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <version>4.0.3</version>
    <scope>test</scope>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webmvc-test</artifactId>
    <version>4.0.3</version>
    <scope>test</scope>
</dependency>

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-test</artifactId>
    <version>7.0.0</version>
    <scope>test</scope>
</dependency>

This configuration adds the core dependencies required for our application. It includes Spring Boot’s web support for building REST endpoints, the Spring Security framework for implementing authentication and authorization, and Spring Security testing utilities for writing security-focused unit tests.

With these dependencies in place, the application now has everything required to configure and enable multi-factor authentication.

4. Enabling Multi-Factor Authentication Globally

Spring Security 7 introduces a convenient annotation called @EnableMultiFactorAuthentication. This annotation allows developers to define which authentication factors are required for all protected endpoints.

The following configuration enables MFA globally using password and X509 authentication factors:

@Configuration
@EnableWebSecurity
@EnableMultiFactorAuthentication(
  authorities = { FactorGrantedAuthority.PASSWORD_AUTHORITY, FactorGrantedAuthority.X509_AUTHORITY }
)
public class GlobalMfaSecurityConfig {
    @Bean
    @Order(3)
    SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
        http.securityMatcher("/**").authorizeHttpRequests(auth ->auth.requestMatchers("/public")
          .permitAll().anyRequest().authenticated()).formLogin(withDefaults());

        return http.build();
    }
}

This configuration enables Spring Security for the application and enables multi-factor authentication globally. As part of the setup, it specifies that the user must complete two authentication factors before the system considers them fully authenticated.

In this case, the required factors are password and X.509 certificate authentication. Once the configuration is active, every secured endpoint in the application requires both factors for access to be granted. Applying MFA globally like this helps avoid inconsistencies and reduces the risk of missing MFA rules in individual authorization configurations.

5. Applying MFA to Specific Endpoints

In many applications, MFA should be required only for sensitive endpoints, such as account settings, financial operations, or admin actions. Spring Security provides the AuthorizationManagerFactory API to define MFA rules programmatically.

The following configuration requires MFA only for admin endpoints:

@Configuration
@EnableWebSecurity
public class AdminMfaSecurityConfig {
    @Bean
    @Order(1)
    SecurityFilterChain adminSecurityFilterChain(HttpSecurity http) throws Exception {
        AuthorizationManagerFactory<Object> mfa = AuthorizationManagerFactories.multiFactor()
          .requireFactors(
            FactorGrantedAuthority.PASSWORD_AUTHORITY,
            FactorGrantedAuthority.X509_AUTHORITY)
          .build();

        http.securityMatcher("/admin/**").authorizeHttpRequests(auth ->auth.requestMatchers("/admin/**")
          .access(mfa.hasRole("ADMIN")).anyRequest().authenticated()).formLogin(withDefaults());

        return http.build();
    }
}

In this configuration, multi-factor authentication is applied only to requests that match the /admin/** endpoints. When a user attempts to access these routes, Spring Security checks whether the required authentication factors are present.

In addition to completing both authentication factors, the user must also have the ADMIN role. This approach provides fine-grained control over security rules, allowing developers to enforce MFA only on sensitive endpoints while keeping the rest of the application accessible with standard authentication.

6. Implementing Time-Based Authentication Rules

Some applications require users to re-authenticate before performing sensitive actions. For example, a banking application may require a fresh login before updating payment information. Spring Security 7 supports time-based MFA rules.

The following configuration requires the user to authenticate the password factor within the last five minutes:

@Configuration
@EnableWebSecurity
public class TimeBasedMfaSecurityConfig {
    @Bean
    @Order(2)
    SecurityFilterChain profileSecurityFilterChain(HttpSecurity http) throws Exception {
        AuthorizationManagerFactory<Object> recentLogin = AuthorizationManagerFactories.
          multiFactor().requireFactor(
            factor -> factor.passwordAuthority().validDuration(Duration.ofMinutes(5)))
          .build();

        http.securityMatcher("/profile", "/profile/**").authorizeHttpRequests(
          auth -> auth.requestMatchers("/profile", "/profile/**")
            .access(recentLogin.authenticated())
            .anyRequest().
            authenticated()).formLogin(withDefaults());

        return http.build();
    }
}

This rule allows users to navigate most parts of the application using their existing authenticated session. However, when a user attempts to access endpoints under */profile/**, the system verifies whether the password authentication was completed recently.

If the password factor is older than five minutes, Spring Security requires the user to authenticate again before granting access. This approach commonly allows users to perform sensitive operations, ensuring they complete critical actions only after a recent, verified authentication step.

7. Implementing User-Based MFA Rules

Sometimes MFA rules apply only to specific users. For example, administrators may be required to use MFA while regular users can log in with a single factor. Spring Security allows implementing custom authorization managers to support such scenarios.

The following example enforces MFA only for the admin user:

@Component
public class AdminMfaAuthorizationManager implements AuthorizationManager<Object> {
    AuthorizationManager<Object> mfa =
      AllAuthoritiesAuthorizationManager.hasAllAuthorities(FactorGrantedAuthority.OTT_AUTHORITY,
        FactorGrantedAuthority.PASSWORD_AUTHORITY);

    @Override
    public AuthorizationResult authorize(Supplier<? extends Authentication> authentication, Object context) {
        Authentication auth = authentication.get();
        if (auth != null && "admin".equals(auth.getName())) {
            return mfa.authorize(authentication, context);
        }
        return new AuthorizationDecision(true);
    }
}

This logic checks the authenticated user’s identity and applies MFA rules conditionally. If the authenticated user is an admin, the system verifies that the user has completed both required authentication factors before granting access.

For all other users, the system allows the request without enforcing additional MFA checks. This approach is useful when introducing MFA gradually, allowing organizations to enforce stronger security for high-privilege users first before extending it to the entire user base.

8. Writing Unit Tests for MFA

Testing authentication flows is essential to ensure that security rules behave as expected. Without proper tests, it becomes difficult to verify whether authentication requirements such as roles, permissions, or MFA factors are correctly enforced.

Spring Security provides dedicated testing utilities that make it easier to simulate authenticated users and validate authorization behavior. These tools allow developers to write focused tests that verify that security configurations function correctly without requiring a full authentication setup.

8.1. Controller Example

Before writing tests, we define a simple controller that exposes the endpoints secured by our MFA configurations:

@RestController
public class DemoController {
    @GetMapping("/public")
    public String publicEndpoint() {
        return "public endpoint";
    }

    @GetMapping("/profile")
    public String profileEndpoint() {
        return "profile endpoint";
    }

    @GetMapping("/admin/dashboard")
    public String adminDashboard() {
        return "admin dashboard";
    }
}

This controller exposes three endpoints /public, /profile, and /admin/dashboard that help demonstrate different MFA enforcement strategies.

8.2. MFA Security Test

This test verifies how the system behaves when it enforces multi-factor authentication globally:

@SpringBootTest(classes = Application.class)
@AutoConfigureMockMvc
class GlobalMfaSecurityTest {
    @Autowired
    MockMvc mockMvc;

    @Test
    void givenUserWithoutMfa_whenAccessProfile_thenForbidden() throws Exception {
        mockMvc.perform(get("/profile").with(user("user").roles("USER")))
          .andExpect(status().is3xxRedirection())
          .andExpect(header().string("Location", containsString("/login")));
    }
}

This test simulates a user attempting to access the admin endpoint without completing the required MFA factors. Since the authentication request only contains the basic role and does not include the necessary factor authorities, the request does not satisfy the configured security rules. As a result, Spring Security returns a 403 Forbidden response because the user has not completed all required authentication factors.

8.3. Admin Endpoint MFA Test

Next, we’ll verify that the system enforces MFA for admin endpoints:

@SpringBootTest(classes = Application.class)
@AutoConfigureMockMvc
class AdminMfaSecurityTest {
    @Autowired
    MockMvc mockMvc;

    @Test
    void givenAdminWithoutMfa_whenAccessAdminEndpoint_thenForbidden() throws Exception {
        mockMvc.perform(get("/admin/dashboard").with(user("admin").roles("ADMIN")))
          .andExpect(status().is3xxRedirection())
          .andExpect(header().string("Location", containsString("/login")));
    }
}

This test simulates an administrator attempting to access the /admin/dashboard endpoint. Although the user has the required ADMIN role, the request does not include the required MFA authorities. Because the authentication factors are incomplete, Spring Security redirects the request to the login page. This confirms that MFA enforcement works correctly for privileged endpoints.

8.4. Time-Based MFA Security Test

Some operations require users to authenticate recently to ensure no one has compromised the session. The following test verifies that the profile endpoint requires a recent authentication:

@SpringBootTest(classes = Application.class)
@AutoConfigureMockMvc
class TimeBasedMfaSecurityTest {
    @Autowired
    MockMvc mockMvc;

    @Test
    void givenUserWithoutRecentAuthentication_whenAccessProfile_thenForbidden() throws Exception {
        mockMvc.perform(get("/profile").with(user("user").roles("USER")))
          .andExpect(status().is3xxRedirection())
          .andExpect(header().string("Location", containsString("/login")));
    }
}

This test checks that the /profile endpoint requires a recent authentication. Since the simulated request does not include the necessary MFA factor information, Spring Security redirects the request to the login page. This confirms that the system correctly enforces the time-based MFA rule.

9. Conclusion

Multi-Factor Authentication (MFA) is a critical security measure for modern applications, helping reduce the risk of unauthorized access by requiring multiple verification factors.

Spring Security 7 provides built-in support for MFA, allowing developers to enforce multiple authentication steps using the existing authorization model. In this article, we explored how FactorGrantedAuthority models MFA, how to enable it globally with @EnableMultiFactorAuthentication, and how to apply it selectively to specific endpoints using AuthorizationManagerFactory. We also covered time-based rules, custom user-based policies, and testing MFA behavior using Spring Security test utilities.

By leveraging these features, developers can build secure and flexible authentication flows. As security threats continue to evolve, implementing MFA is no longer optional but an essential step in protecting user data and critical systems. As always, the code for this example is available over on GitHub.

Baeldung Pro – NPI EA (cat = Baeldung)
announcement - icon

Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:

>> Explore a clean Baeldung

Once the early-adopter seats are all used, the price will go up and stay at $33/year.

eBook – HTTP Client – NPI EA (cat=HTTP Client-Side)
announcement - icon

The Apache HTTP Client is a very robust library, suitable for both simple and advanced use cases when testing HTTP endpoints. Check out our guide covering basic request and response handling, as well as security, cookies, timeouts, and more:

>> Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

Course – LS – NPI EA (cat=REST)

announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (tag=Refactoring)
announcement - icon

Modern Java teams move fast — but codebases don’t always keep up. Frameworks change, dependencies drift, and tech debt builds until it starts to drag on delivery. OpenRewrite was built to fix that: an open-source refactoring engine that automates repetitive code changes while keeping developer intent intact.

The monthly training series, led by the creators and maintainers of OpenRewrite at Moderne, walks through real-world migrations and modernization patterns. Whether you’re new to recipes or ready to write your own, you’ll learn practical ways to refactor safely and at scale.

If you’ve ever wished refactoring felt as natural — and as fast — as writing code, this is a good place to start.

Course – Summer Sale 2026 – NPI EA (cat= Baeldung)
announcement - icon

Yes, we're now running our only Summer Sale. All Courses are 30% off until 20th July, 2026:

>> EXPLORE ACCESS NOW

Course – Summer Sale 2026 – NPI (All)
announcement - icon

Yes, we're now running our only Summer Sale. All Courses are 30% off until 20th July, 2026:

>> EXPLORE ACCESS NOW

eBook Jackson – NPI EA – 3 (cat = Jackson)