Multi-Factor Authentication with Spring Boot 2 and Spring Security 5
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Multi-factor authentication in Spring Boot 2 is usually built as a two-step login flow: password first, then a second factor such as a time-based one-time password. Spring Security 5 gives you the authentication hooks, but you still need to decide how to represent the intermediate state between "password accepted" and "fully authenticated."
Model MFA as Two Distinct Steps
A clean mental model is:
- verify username and password
- if the user has MFA enabled, require an OTP before granting full access
That means a successful password check does not always mean a complete login. Instead, it may mean "first factor passed, continue to OTP verification."
A simple user entity might look like this:
The important fields are the MFA flag and the TOTP secret used to validate the second factor.
Authenticate the Password First
Your normal UserDetailsService and password encoder still handle the first factor. The difference is what happens after the password is correct.
In a real application you would load the user from a database. The key design choice is whether the authentication success handler sends the user directly to the app or redirects to an MFA screen.
Redirect to an MFA Verification Step
A common pattern is to store a temporary marker in the session after password login, then redirect to /mfa.
This is easier to reason about than trying to overload one authentication object with both incomplete and complete states.
Verify the TOTP Code
For the second factor, many Spring applications use a TOTP library such as Google Authenticator compatible code generation. The service interface can stay simple.
Then a controller can complete the MFA flow:
This example is intentionally simplified, but the flow is the important part: pending state first, verified state second.
Configure Spring Security Around the Flow
Your security configuration should allow access to the login page and MFA page, but require a completed login for protected resources.
In a production system, you would also add logic that blocks access to the rest of the application when MFA is still pending.
Do Not Forget Recovery and Secret Storage
A working OTP screen is only the start. A real MFA implementation also needs:
- encrypted storage for the TOTP secret
- enrollment flow with QR code provisioning
- backup or recovery codes
- rate limiting on OTP attempts
- audit logging for second-factor failures
Without recovery handling, MFA turns into a support problem as soon as users lose their authenticator app or replace a phone.
Common Pitfalls
The biggest mistake is treating password success as full authentication even for users who should still pass a second factor. Another common issue is storing the TOTP secret in plain text or handling OTP verification without rate limiting. Developers also often forget recovery flows, which makes MFA impossible to support operationally. Finally, the intermediate "MFA pending" state must be handled carefully so partially authenticated users cannot reach protected endpoints.
Summary
- A practical Spring Boot 2 and Spring Security 5 MFA flow is usually password first, OTP second.
- Model the post-password state as "MFA pending" rather than fully authenticated.
- Verify the TOTP code in a dedicated step such as
/mfa. - Securely store secrets and plan for recovery, rate limiting, and auditing.
- The security challenge is not only generating OTPs, but also correctly representing incomplete versus complete authentication.

