Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

MikeHopley's avatar

Cannot pass message to user when session has expired

By default, TokenMismatchException produces a user-hostile 500 internal server error. I'm trying to handle it in a more friendly way.

The problem is that I cannot pass an error message back to the user once the session has timed out.

In app/Exceptions/Handler.php, I check for the TokenMismatchException and try to redirect the user back with a message:

public function render($request, Exception $e)
    {
        if ($e instanceof TokenMismatchException)
        {
            return redirect()->back()->with( 'csrf_error', 'Sorry, your session timed out. Please try again.' );
        }

        return parent::render($request, $e);
    }

Now, a token mismatch can occur for two reasons: the token is wrong/missing, or expired. If I delete the token field and submit the form, everything works as expected: the user is redirected back and shown the error message.

But if I let the session expire (by setting the session lifetime to 0.1), then it doesn't work. The user is redirected back, but there is no error message.

I think this may be happening because the session has not yet been recreated, so the message has nowhere to be stored?

0 likes
6 replies
Snapey's avatar

Once the session expires, the next request from the user does not match to anything - it's just treated as a brand new request, you can't differentiate them from a brand new visitor.

It works if you delete the csrf token because the session still persists.

are you sure the user is redirected back through your exception handler and not for some other reason?

MikeHopley's avatar

are you sure the user is redirected back through your exception handler and not for some other reason?

Yes. I've tested that with a die statement instead, as well as redirecting them to a different page.

Once the session expires, the next request from the user does not match to anything - it's just treated as a brand new request, you can't differentiate them from a brand new visitor.

I just need some way of sending a message along with the request. I don't need to identify it with the previous session.

When/how does the next session get started?

I suppose one way to handle it would be to append a query string to the redirect URL and detect the csrf error state based on that. Sounds like a pretty messy solution.

Snapey's avatar

These are unauthenticated users that are submitting the forms?

I ask because there is a question about which middleware is checked first. If the session expires, then is the session checked first to find out if they are allowed to post, or is the csrf checked first.

If the session is checked first then I would just expect the user to be directed to the login page.

1 like
MikeHopley's avatar

Thanks for explaining about the middleware.

At the moment I don't know which forms or users are generating these errors, although I've started logging more information to investigate.

I think for now I'm just going to wait for more information, and extend the session lifetime.

bashy's avatar

What about redirecting them back with the new token + a message?

// app/Exceptions/Handler.php
public function render($request, Exception $exception)
{
    // Redirect back with input if token is wrong/expired
    if ($exception instanceof TokenMismatchException) {
        return back()
            ->withInput($request->merge(['_token' => csrf_token()]))
            ->with('error', 'Security token wrong or expired - please submit again.');
    }

    return parent::render($request, $exception);
}

Just pick it up with {{ session()->get('error') }} in the view somewhere

1 like
MikeHopley's avatar

Hmm, that would be great if it worked. The trouble is, I don't seem to be able to pass the error message once the session has expired.

Thanks for the suggestion though, I will give it a quick try and see if it works!

EDIT Nope, no luck. That functions just the same as my original code. :(

Also, it seems that a new token is generated anyway. The problem is the message.

I'm beginning to suspect that these exceptions are not from real users anyway, given I have a long session lifetime. Could be bots. :/

Please or to participate in this conversation.