[Security][SecurityBundle] Add IS_AUTHENTICATED_RECENTLY to require a fresh authentication - #66014
Open
nicolas-grekas wants to merge 1 commit into
Open
[Security][SecurityBundle] Add IS_AUTHENTICATED_RECENTLY to require a fresh authentication#66014nicolas-grekas wants to merge 1 commit into
nicolas-grekas wants to merge 1 commit into
Conversation
94noni
reviewed
Sep 11, 2026
nicolas-grekas
commented
Sep 11, 2026
Member
Author
|
Edit: the below note is addressed in #66035 With the current approach, it's pretty obvious that the strategy will eventually end up asking users to re-authenticate every N minutes, which is not necessarily the best UX. There are typically other risk factors that could contribute to a "recent-enough" decision; e.g. whether the IP address changed since the last authentication, a last-activity timer, a combination of those signals, a recent WebAuthn/MFA confirmation, etc. The current time-based strategy still makes perfect sense as a simple default, but I think |
nicolas-grekas
force-pushed
the
is-authenticated-recently
branch
2 times, most recently
from
September 13, 2026 08:42
a8e6423 to
c455e1a
Compare
… 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
is-authenticated-recently
branch
from
September 13, 2026 08:54
c455e1a to
94bf766
Compare
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.The rest of the stack
This is the base of a three-PR stack; each part is reviewable and mergeable on its own.
auth_timeclaim feeding the same stamp, somax_ageand sudo mode agreeDocs 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.