Close #213: honor post-success listeners that may block authentication#316
Open
giosh94mhz wants to merge 1 commit intoscheb:7.xfrom
Open
Close #213: honor post-success listeners that may block authentication#316giosh94mhz wants to merge 1 commit intoscheb:7.xfrom
giosh94mhz wants to merge 1 commit intoscheb:7.xfrom
Conversation
…cation A provider is marked as resolved only during TwoFactorAuthenticator::onAuthenticationSuccess that is called after the whole Symfony late authentication checks are completed. This will restore the functionality of UserCheckerInterface::checkPostAuth that may block the authentication based on post-login user constraints.
scheb
reviewed
May 6, 2026
| $twoFactorToken = $credentialsBadge->getTwoFactorToken(); | ||
|
|
||
| // Provider complete can only be marked this onAuthenticationSuccess, since others auth listener may still trigger failures | ||
| // $twoFactorToken->setTwoFactorProviderComplete($twoFactorToken->getCurrentTwoFactorProvider()); |
Owner
There was a problem hiding this comment.
I'm wondering where in the process the provider is marked as completed, if it's no longer happening in AbstractCheckCodeListener.
Should this line actually be un-commented?
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Symfony’s standard authentication includes several "post-checks" that run immediately after a successful login, most notably
TwoFactorAuthenticator::onAuthenticationSuccess.Starting with Symfony 7.x and 2fa-bundle 7.x (and possibly others), these listeners can generate a loop-redirect, as described in #213.
The Issue
The root cause is that
TwoFactorTokenmarks a provider as completed during badge verification. If an error occurs after this stage, the entire login process is left in an inconsistent state for several reasons:getTwoFactorProviders) are empty, so the active token inTokenStorageis inconsistentThe Solution
During badge verification, providers must not be marked as complete in the
TwoFactorToken, as this happens too early in the process. This is critical to keepTwoFactorTokenInterface::getCurrentTwoFactorProviderstable throughout the request and avoid the loop issue.Instead, we need to identify another point to mark the
TwoFactorTokenprovider as complete—ideally, at the very end of the authentication process.By examining the
Symfony\Component\Security\Http\Authentication\AuthenticatorManager::executeAuthenticatorclass, I see that theAuthenticationEvents::AUTHENTICATION_SUCCESSevent (whereUserCheckersand other checks run) is considered part of the standard process, as it is within the try-catch block. Immediately after this event,$authenticator->onAuthenticationSuccessis called, making it the right place to mark the flow as completed.Therefore, the solution is to mark the current provider for any
TwoFactorTokenthat reachesTwoFactorAuthenticator::onAuthenticationSuccessas completed—not before.Tests
I ran many tests in my application, which uses both stateful and stateless authenticators, as well as multiple post-authentication locks, and everything seems to work. However, we only have one OTP method, so the code for handling multiple OTP methods and
$this->dispatchTwoFactorAuthenticationEvent(TwoFactorAuthenticationEvents::REQUIRE, $request, $token)still needs some testing.Minor Breaking Changes
I foresee two minor breaking changes:
TwoFactorTokenInterface::getCurrentTwoFactorProvider, e.g. fromnulltototp(though this is likely a fix rather than an issue, IMO).TwoFactorTokenInterface::allTwoFactorProvidersAuthenticatedmethod will likely never returntrue, since the previous token forgot afteronSuccessfulAuthentication.The main struggle with
TwoFactorTokenInterfaceis that thesetTwoFactorProviderCompletemethod actually removes a provider from the token, which can cause glitches. My patch addresses this by requiring the authenticator to estimate the "on complete" status by comparinggetTwoFactorProvidersand the active providers.Regarding point 2, I may update the
TwoFactorTokeninside the authenticator success so thatTwoFactorTokenInterface::allTwoFactorProvidersAuthenticatedis updated for potential external classes still referencing the token and triggering in post-success events, likeTwoFactorAuthenticationEvents::COMPLETE.In a future release,
TwoFactorTokenInterfacemay need a cleanup or an improvements to avoid this edge cases.