Skip to content

feat(http)!: regenerate the session identifier on authentication - #2284

Open
osbre wants to merge 2 commits into
tempestphp:3.xfrom
osbre:feat/session-regeneration
Open

feat(http)!: regenerate the session identifier on authentication#2284
osbre wants to merge 2 commits into
tempestphp:3.xfrom
osbre:feat/session-regeneration

Conversation

@osbre

@osbre osbre commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

The session identifier used to survive authentication, so an identifier an attacker planted before login stayed valid afterwards and granted them the authenticated session.

SessionRegenerator assigns a new identifier to the current session and destroys the session it replaces. SessionAuthenticator calls it when authenticating and deauthenticating.

This is what OWASP ASVS 5.0 requires under 7.2.4 at level 1, including the termination of the previous token, and what both Laravel and Symfony do by default.

Breaking changes

  • SessionIdResolver gains a regenerate() method, which custom resolvers must implement.
  • SessionAuthenticator no longer takes a SessionManager, and takes a SessionRegenerator instead.
  • Deauthenticating now discards the session data instead of carrying it over to the new identifier, matching Laravel and Symfony. Authenticating still preserves it, so flash data and the intended URL survive a login.

@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown

Benchmark Results

Comparison of feat/session-regeneration against 3.x (b3300355561e054443b93dbccad0f5a6403ade20).

Open to see the benchmark results
Benchmark Set Mem. Peak Time Variability
GenericRouterBench(benchDispatchWithoutMiddleware) Static route 5.264mb 0.00% 30.802μs +5.17% ±0.97% -39.63%
ViewRenderBench(benchExpressions) - 24.592mb 0.00% 366.719μs +10.50% ±3.24% +27.04%
ContainerBench(benchRegisterDefinition) - 6.776mb 0.00% 1.708μs +8.11% ±0.92% -73.98%
DiscoveryScanBench(benchSinglePackageScan) clock (small) 25.861mb +0.02% 49.359μs +6.35% ±2.26% -8.61%

Generated by phpbench against commit 9321d08

@brendt brendt left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not add the regenerate logic in the manager class?

@osbre

osbre commented Sep 7, 2026

Copy link
Copy Markdown
Contributor Author

Since SessionManager is an interface, adding it there would lead to duplication as all regenerate does is:

  1. deleting the old session
  2. swapping the ID via the resolver
  3. saving the new one

It doesn't seem to be storage-specific, so all three managers would end up repeating the same code. It would also mean injecting the SessionIdResolver into every implementation.

@osbre
osbre requested a review from brendt September 7, 2026 14:00
@innocenzi

Copy link
Copy Markdown
Member

I agree with @osbre regarding the responsibility of SessionManager.

I cleaned the API a bit by renaming methods to better names, and removing preserveData in favor of a dedicated method.

One thing I don't like but don't have a solution for is replaceId. It makes no sense for userland to ever reach it, but there isn't anyplace else to put it either. We can't just update Session in the container because it could be stale in other dependencies.

If you have any idea, I'll take it; otherwise we can just keep it as @internal, but it's not ideal.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants