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

connor11528's avatar

419 error when submitting form in production - Sorry, your session has expired. Please refresh and try again

I've got a Laravel 5.7 app that is working locally. For instance, when running locally I'll get flash messages about failed validation and it shows fine in the blade view:

I do have the @csrf helper in my blade form.

When I deploy and submit the form on production I get a 419 error: "Sorry, your session has expired. Please refresh and try again". Redirects are not working for social login with google or linkedin in production, though they're working locally.

I am using Laravel Forge for production and database tables for session and cache. So my .env file for production is:

BROADCAST_DRIVER=log
CACHE_DRIVER=database
SESSION_DRIVER=database
QUEUE_DRIVER=sync

I have tried changing the APP_NAME and APP_KEY and deleting all the contents of the "sessions" table as well but the 419 error persists on production.

Then my deployment script for Laravel Forge is:

cd /home/forge/employbl.com
git reset --hard origin/master
git pull origin master
composer install --no-ansi --no-dev --no-interaction --no-progress --no-scripts --optimize-autoloader
echo "" | sudo -S service php7.2-fpm reload
rm -rf node_modules
composer dump-autoload
php artisan config:clear
php artisan view:clear
php artisan responsecache:clear
php artisan config:cache
php artisan migrate --force
php artisan sitemap:generate 

How can I clear the sessions so I don't get the 419 "your session has expired" and the form works on the production server?

0 likes
33 replies
midwestdev's avatar

Do you also have the csrf in the header of your application?

<meta name="csrf-token" content="{{ csrf_token() }}">
connor11528's avatar

@MIDWESTDEV - Yes I do I have <meta name="csrf-token" content="{{ csrf_token() }}"> in the <head> of the application

roerjo's avatar

As a temp solution you could try commenting out the CSRF middleware in your web middleware group.

roerjo's avatar

Also, check the permissions on production for storage/framework/sessions. I believe they need to be either 600 or 660

midwestdev's avatar

What does your session data in chrome developer tools say?

connor11528's avatar

@ROERJO - Hmm, like this?

    protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            \Illuminate\Session\Middleware\AuthenticateSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            // \App\Http\Middleware\VerifyCsrfToken::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
            \Spatie\ResponseCache\Middlewares\CacheResponse::class,
        ],

Something to think about, but i'm kinda sketched out about getting hacked

roerjo's avatar

@connor11528 yeah that should just be a temp solution to help debug...would want to re-enable on production asap once the bug is figured out...but did you checkout my other reply? I have a sneaking suspicion that it is a permissions issue

midwestdev's avatar

Yep, that is what he means. Just make sure it is temporary while you do the rest of the development. Just make sure you note to come back to it later. Other things you can try, include of course changing environments, browsers, and whatever else you need to isolate the issue.

connor11528's avatar

@ROERJO - Okay so set the permissions for storage/framework/sessions? I might need to SSH into the machine for that. I originally had sessions being stored as "file" and switched them to be stored in "database"

roerjo's avatar

@connor11528 if you were using file based sessions then they would be stored in storage/framework/sessions...but if you switched to database sessions then that should not longer be the case. Can you confirm that your production .env file is set to use database sessions and not file based sessions? Maybe also double check your config/sessions.php setup.

tykus's avatar

When you switched, did you run the migration needed by the database sessions? There is an artisan command to generate the migration, php artisan session:table, then migrate php artisan migrate.

1 like
roerjo's avatar

along with @tykus suggestion, if they did migrate, are they populating since your last deployment?

1 like
roerjo's avatar

@tykus in his original post it looks like he had php artisan migrate --force as part of his deployment script

tykus's avatar

@roerjo it's not worth anything if the migration to create the sessions table is not there.

1 like
connor11528's avatar

@ROERJO - Yes I switched to "database" for session permissions. My .env file looks like:

BROADCAST_DRIVER=log
CACHE_DRIVER=database
SESSION_DRIVER=database
SESSION_DOMAIN=null
SESSION_COOKIE=employbl
QUEUE_DRIVER=sync

and in config/session.php I have 'driver' => env('SESSION_DRIVER', 'database'),.

Confirmed that the session table is being created and populated with records on my production database.

Just in case I SSH'd into my forge server and checked file permissions, it looked like:

forge@Employbl:~/employbl.com$ ls
CNAME      composer.json  nova               resources   vendor
README.md  composer.lock  package-lock.json  routes      webpack.mix.js
app        config         package.json       server.php  yarn.lock
artisan    database       phpunit.xml        storage
bootstrap  laradock       public             tests
forge@Employbl:~/employbl.com$ ls -l
total 1248
-rw-rw-r--  1 forge forge     17 Jul 12  2018 CNAME
-rw-rw-r--  1 forge forge   2468 Feb 20 00:58 README.md
drwxrwxr-x 10 forge forge   4096 Feb 21 17:58 app
-rw-rw-r--  1 forge forge   1686 Jul 12  2018 artisan
drwxrwxr-x  3 forge forge   4096 Jul 12  2018 bootstrap
-rw-rw-r--  1 forge forge   2137 Feb 21 02:22 composer.json
-rw-rw-r--  1 forge forge 238627 Feb 21 02:22 composer.lock
drwxrwxr-x  2 forge forge   4096 Feb 21 17:58 config
drwxrwxr-x  7 forge forge   4096 Feb 19 23:02 database
drwxrwxr-x  2 forge forge   4096 Oct 19 23:37 laradock
drwxrwxr-x  9 forge forge   4096 Oct 29 22:41 nova
-rw-rw-r--  1 forge forge 729852 Feb  3 05:57 package-lock.json
-rw-rw-r--  1 forge forge   1457 Feb  3 05:57 package.json
-rw-rw-r--  1 forge forge   1142 Dec 27 05:01 phpunit.xml
drwxrwxr-x  8 forge forge   4096 Feb 21 18:52 public
drwxrwxr-x  5 forge forge   4096 Jul 12  2018 resources
drwxrwxr-x  2 forge forge   4096 Feb 21 18:47 routes
-rw-rw-r--  1 forge forge    563 Jul 12  2018 server.php
drwxrwxr-x  6 forge forge   4096 Jul 12  2018 storage
drwxrwxr-x  4 forge forge   4096 Dec 27 05:01 tests
drwxrwxr-x 42 forge forge   4096 Feb 21 18:52 vendor
-rw-rw-r--  1 forge forge    570 Jul 15  2018 webpack.mix.js
-rw-rw-r--  1 forge forge 218035 Jul 12  2018 yarn.lock
connor11528's avatar

@TYKUS - I do have create session and create cache migrations. The "sessions" table is being created and in my config/sessions.php I have 'table' => 'sessions',. Session records are populating in the sessions table in production

roerjo's avatar
roerjo
Best Answer
Level 19

On your production form I am seeing a token generated but I am also seeing cookie token being generated:

set-cookie: XSRF-TOKEN=eyJpdiI6IllnUTV6QnZpRjZQaGN5dk9ETGFnOVE9PSIsInZhbHVlIjoic2xVZ0MyYTlzODFHamNmZ1A3NGlueVFWWk4xWHpnOHNrZ2VqWVlDMVVYTmtLaWdzZ1RsYnVENFBhSms3QXRVOSIsIm1hYyI6ImIzNTFkZjk2YjViMmViOGVlYTJhNmFhMGFmNzQ2NzRhYTBlOGQ1OWQ5ODNlYWZmYjMxZjZkYTI0MzdlNDY5OWUifQ%3D%3D; expires=Thu, 21-Feb-2019 23:43:24 GMT; Max-Age=7200; path=/

The hidden input token value is completely different.

I'm getting into the weeds on this with my knowledge, but are you somehow setting both a cookie token and db token?

1 like
roerjo's avatar

What does your VerifyCsrfToken class look like?

roerjo's avatar

Another debug option would be to try switching back to file sessions if those were working before. Maybe it is an issue with the database driver.

1 like
connor11528's avatar

@ROERJO -

<?php

namespace App\Http\Middleware;

use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;

class VerifyCsrfToken extends Middleware
{
    /**
     * The URIs that should be excluded from CSRF verification.
     *
     * @var array
     */
    protected $except = [
        //
    ];
}
roerjo's avatar

@connor11528 Did you by chance change anything from the default sessions table configuration?

Default:

Schema::create('sessions', function ($table) {
    $table->string('id')->unique();
    $table->unsignedInteger('user_id')->nullable();
    $table->string('ip_address', 45)->nullable();
    $table->text('user_agent')->nullable();
    $table->text('payload');
    $table->integer('last_activity');
});
connor11528's avatar

@ROERJO - This is super helpful. not sure why this is happening but comparing these two values seems definitely to be on to the issue root cause. So you inspect the hidden input field and that value should be present on the form submit request in network tab?

roerjo's avatar

@connor11528 Yeah the token that is generated in the hidden input needs to match the token stored in the session.

connor11528's avatar

@ROERJO - Okay I ran the deploy with the new app key generation (with force), deleted sessions from database and file system and cleared the cookies in the chrome browser.

Still getting the 419.

When I check the cookie data in chrome (chrome://settings/siteData) it shows I'm creating an XSRF-TOKEN and a cookie with name employbl (comes from SESSION_COOKIE env variable)

I'm thinking that I shouldn't be creating that XSRF-TOKEN in the browser or that somehow what I'm storing isn't matching up to the server somehow

roerjo's avatar

@connor11528 another debug tip: ssh into your prod server and nav to you codebase..in forge I believe it puts it in ~/{repo}/current? From there, run php artisan tinker and then run getenv() to dump all the server environment variables...you can then confirm that php has pulled in the correct setup.

1 like
roerjo's avatar

@connor11528 That cookie XSRF-TOKEN isn't the issue I think. I checked a personal project and I have the same cookie but it isn't creating any conflicts. Have you tried reverting back to file based sessions to see if those worked?

1 like
connor11528's avatar

Alright got rid of the 419. I needed to clear the cache with php artisan cache:clear

Flash messages are still not showing up but that could be a different error. Thank you SO MUCH for your help @roerjo

1 like
Next

Please or to participate in this conversation.