[Security][SecurityBundle] Add IS_AUTHENTICATED_RECENTLY to require a fresh authentication - #66001
Closed
nicolas-grekas wants to merge 1 commit into
Closed
Conversation
… fresh authentication Records the time of the last interactive authentication as the `auth_time` token attribute, and grants IS_AUTHENTICATED_RECENTLY while it is within the configured lifetime. This is what lets a sensitive action ask the user to prove possession of their credentials again instead of trusting a session opened long ago.
nicolas-grekas
force-pushed
the
feature/is-authenticated-recently
branch
from
September 11, 2026 12:55
56462ac to
146ca77
Compare
Member
Author
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.
Sudo mode, asked for in #33955 seven years ago. The demand was never in question (@fabpot in 2022: "there are no questions about 'do we want it?'. It's more like, 'who wants to work on it?'"), but the issue was parked behind the broader "identity trust level" model in #39308, and both that issue and #30914 have since been closed without it. So this takes the self-contained route.
What it does
IS_AUTHENTICATED_FULLYdescribes how the session began, never how recently the user proved possession of their credentials. This adds a second axis:Three pieces:
AuthenticationTimeListenerrecords the moment of an interactive authentication as theauth_timetoken attribute.auth_timeis the name OIDC Core already uses for this, which keeps the door open for the ID token claim to feed the same stamp later.AuthenticatedVotergrantsIS_AUTHENTICATED_RECENTLYwhile that stamp is within the configured lifetime.is_recently_authenticated()in the expression language andIsGrantedContext::isAuthenticatedRecently()for the closure form, matching the existingis_fully_authenticated()pair.Design notes
AbstractToken::__serialize()already includes$attributes, andContextListener::refreshUser()mutates the token in place rather than rebuilding it, so the stamp survives the session round trip on its own. A functional test asserts exactly that rather than trusting it.IS_AUTHENTICATED_RECENTLYis strictly stronger thanIS_AUTHENTICATED_FULLY, so being fully authenticated does not grant it. A token with noauth_timeis denied, which is the safe default for non-interactive authenticators.RememberMeAuthenticator::isInteractive()returnstrue, so a remember-me login does get stamped; theisFullFledged()guard is what keeps it denied. That is covered by a test, since it is the one place the feature could silently go wrong.Psr\Clock\ClockInterface, wired asservice('clock')->nullOnInvalid(), which is the idiom FrameworkBundle itself uses atResources/config/services.php:110andweb.php:66.clockis defined unconditionally by the DI kernel and aliased for bothClockInterfaceflavours, so a real application always gets it; thetime()fallback only covers standalone use of the components, so neither package needs a new dependency. A functional test asserts the clock actually arrives, sincenullOnInvalid()would otherwise let a wrong service id fall back totime()unnoticed.Deliberately not in scope
access_denied_handler. Worth doing, but it is a separate surface and this is already reviewable on its own.auth_timeclaim into the same stamp, somax_ageand sudo mode agree.Docs to follow once the shape is agreed.
Thanks @javiereguiluz for the original RFC, and @stof and @wouterj for the constraints in the thread that shaped this.