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

dfriend's avatar

CSRF - Form Token Doesn't Match Session Token

Hi, Ive been stuck on this for a few hours now, hopefully i can get some guidance --- using Laravel 5 -

Basically Im getting a token mismatch exception - the token populated in my form doesn't match the Session token....

Ive tried various token variables and none are able to provide the 'Session' token i see in the debugger. Here is a quick example: (i had this display on the same page)

Session::getId() = 348c38aec02593e406b01b60e8d10ad40ca6bc73 Session::token()= Hdlp2AeY7WiObE1P0RDzB7dcWD6STl3awe2SLVGK csrf_token()=Hdlp2AeY7WiObE1P0RDzB7dcWD6STl3awe2SLVGK

The Session token from the debugger is "'R2OB65jZB1Fm6cnZKrFzvc2XAMJppR79GHxci9Xe"

In my DB Sessions table - the only token of these three recorded is from "Session::getId()"

Any ideas or fixes to get my tokens to match up?

Don

0 likes
35 replies
dfriend's avatar

OK - Update on this - the problem is that another session is being created by the POST request with my form data. Thus when the tokens are matched, they are different.

Any ideas on how to deal with this?

Don

jhaoda's avatar

This happens when a POST request over AJAX is cross-domain and not properly configured.

dfriend's avatar

Hi Jhaoda- thanks for your help- the request is originating from the "action" html tag of the form using a relative URL. Eg action="registration" to send the form data to localhost/registration -- so I'm not sure why it would be cross-domain, but if so, how do I fix it?

lukas's avatar

found "the solution" here:

http://stackoverflow.com/questions/27304060/correctly-set-headers-for-laravel-5-csrf-token

"This is due to encryption of the csrf token. Laravel expect the token to be encrypted. It tries to decrypt the the plain token you provide and it fails. Before you can use the token in the header you have to encrypt it.

$encrypter = app('Illuminate\Encryption\Encrypter');
$encrypted_token = $encrypter->encrypt(csrf_token());"

Hope this will help somebody. I've lost almost 4 hours to figure out...

3 likes
lukas's avatar

laravel 5:

  • in blade:
<?php
    $encrypter = app('Illuminate\Encryption\Encrypter');
        $encrypted_token = $encrypter->encrypt(csrf_token());
 ?>
<input id="token" type="hidden" value="{{$encrypted_token}}">
<script>
.....
var $_token = $('#token').val();
....
$.ajax({
                type: 'post',
                cache: false,
                headers: { 'X-XSRF-TOKEN' : $_token }, 
                url: 'the_url_to_controller_thru_route/' + some_parameters_if_needed,
                //contentType: "application/json; charset=utf-8",
                //dataType: 'json',
                data: {personid: 873}, //assuming that you send some data like id of a person to controller 
                                success: function(data) {
....
</script>
  • route:
Route::post('the_url_to_controller_thru_route/{some_parameters_if_needed}', 'TheController@postIdFromBladeThruAjax');
  • in TheController.php
public function postIdFromBladeThruAjax(some_parameters_if_needed)
{
          if(\Request::isMethod('post') && \Request::ajax())
            {
                $personid = \Input::get('person'); 
                if(!empty($personid))
                    {
                        \Log::info('json: '.$personid);
                                 return response()->json(['success' => true, 'personid'=>$personid ]); 
                } else { return response()->json(['error']=>true, 'msg'=>'some err message']);}
        }
....
}
4 likes
pmall's avatar

Doesn't X-CSRF-TOKEN allow to thow the token unencrypted ?

1 like
lukas's avatar

Well yes and no, the Middleware (\App\Http\Middleware) is using VerifyCsrfToken.php, wich can be disabled (to not verify the token) from \App\Http\Kernel.php

I'ts your choice if you want your app to be secure ... Actually if you send it unencrypted you'll get an error message (exception) because the comparation is made against the encrypted _token.

unencripted:

<pre> 
    {{\Session::token() }}
    or 
        {{crsf_token()}}
</pre>

encript it using the encription and compare you'll se that every time is different. So is more secure for your app to use token. Hope that's help.

See more please on official docs: http://laravel.com/docs/master/routing (CSRF Protection).

pmall's avatar

Yes, from the doc :

<meta name="csrf-token" content="{{ csrf_token() }}" />

$.ajaxSetup({
    headers: {
        'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
    }
});

No need to encrypt the token when posting through ajax. My question was rhetorical.

Oilop9000's avatar

Well, I had the same issue but I decided to take another approach, looking into the Laravel 5 Authentication that was included. The thing is, that the L5 Auth Controller, Trait, View, uses non encrypted csrf tokens as lukas said, and the only difference I saw between my own views and Laravel's Auth Views was that the

<input type="hidden" name="_token" value="{{ csrf_token() }}"> 

was just after the open form tag as in:

<form class="form-horizontal" role="form" method="POST" action="../auth/login">
                        <input type="hidden" name="_token" value="{{ csrf_token() }}">
....

I've changed the order and worked like a charm, so hope this help others.

elporfirio's avatar

We cant use csfr_token() in a NO Laravel APP, then when you ask with AJAX the missmatch still happening. I Make a route for return Session::token() but it doesnt work. All examples over internet use the same domain. Or API and frontend was build on Laravel. Useless

Piro's avatar

Hey Buddies! I'am new here and need some helps from the masters of Laravel. I'am using laravel 5. When i change the driver of session to database i get this error: TokenMismatchException in VerifyCsrfToken.php line 46:

How can i fix it?

Thanks

vitr's avatar

@Piro, did you try to refresh the page after the session driver switch?

kenmoini's avatar

The solution produced by @lukas worked great for me...probably not the cleanest/best way of doing it, but works without issues.

codesidekick's avatar

I had the same problem recently and fixed it. The reason was because there was a blank line at the beginning of one of my php files. Visit a page and check if there's a space before your doctype tag (right at the top of the source code). If there is, chances are you've put a space before one of the <?php opening tags in one of the files and, for whatever reason, that breaks all cookies on the site and Laravel is unable to create a session.

blueminded's avatar

Hey @codesidekick thank you. I was having this problem in my Mac, I mean It worked fine in Windows but in mac it crushed. After searching a lot on the web, finally solved the problem.

By the way, I am using Laravel Debugger Bar and it is also affected by this problem, very weird. I hope this help others.

Take a look.

It should look like https://dl.dropboxusercontent.com/u/3475543/Captura%20de%20pantalla%202015-07-11%20a%20las%2011.21.56%20a.m..png

but It was displayed like https://dl.dropboxusercontent.com/u/3475543/Captura%20de%20pantalla%202015-07-11%20a%20las%2011.19.18%20a.m..png

wyl206's avatar

It is that the ob_start, ob_get_clean don't work synchronously in the view process causes the problem. In this circumstance, the view process echoes the content of site first anomalously before the response sends cookie, headers, and content. So the browser doesn't receive header correctly. Next time the browser send request, the session id mismatches because lack of correct cookies, then trigger the CSRF token mismatch problem. Details are in here: https://github.com/wyl206/Web/blob/master/laravel/myTokenMismatchProplem.md

The solution is simple. That is to maintain it is in the same output buffering level after excuted "include $__path". So I change the evaluatePath function in file "Illuminate\View\Engines\PhpEngine.php". Here is my solution Code:

protected function evaluatePath($__path, $__data)
{

    $obLevel = ob_get_level();
    extract($__data);
    ob_start();
    $obStartLevel = ob_get_level();

    // We'll evaluate the contents of the view inside a try/catch block so we can
    // flush out any stray output that might get out before an error occurs or
    // an exception is thrown. This prevents any partial views from leaking.
    try {

        include $__path;

    } catch (Exception $e) {
        $this->handleViewException($e, $obLevel);
    } catch (Throwable $e) {
        $this->handleViewException(new FatalThrowableError($e), $obLevel);
    }

    //最终是要保证obEndLevel和obStartLevel在同一层
    $obEndLevel = ob_get_level();
    while($obEndLevel > $obStartLevel){
        ob_end_flush(); 
        $obEndLevel = ob_get_level();
    }
    $myContent = ltrim(ob_get_contents());
    while($obEndLevel < $obStartLevel){
        ob_clean();  
        if(!ob_start())  break; 
        $obEndLevel = ob_get_level();
    }
    if($obEndLevel === $obStartLevel) ob_end_clean();
    return $myContent;
}
1 like
froind's avatar

Had the same problem with the token mismatch exception in ajax calls being thrown after some work on my app. Did a little snooping around and found that laravel created a new session for each ajax call with a different token. It all turned out to be because of a couple of dump() calls in my routes. So, try removing all calls to dump() in your route.

gbrock's avatar

I fixed this in my case by clearing Laravel's file cache (deleting cache files from storage/framework/sessions and storage/framework/views).

wurkhouse's avatar

This helped me. Open terminal and run.

php artisan session:table

Then migrate and test again

php artisan migrate

Khudadad's avatar

I think if you clear Your browser cache it'll work.

jslocum's avatar

I did some searching and didn't find any solutions exclusively using Guzzle 6.x and Laravel 5.2 to send POST requests to upload jpeg image files with crsf token matching enabled. I wanted to use the same Laravel route that I used to upload files from dropzonejs. I wanted to use a PHP script to load existing images from another location into the new image server. dropzonejs sends the request and uses the csrf token.

On the Guzzle client side:

$url_base = "http://{someserver.dev}/";
$path = "{someImageFolderPath}/";
$fileName = "{someImageFileName.jpg}";
$filePath = $path.$fileName;
$mime = "image/jpg";

//instantiate Guzzle Client and cookie jar
$client = new Client;
$jar = new CookieJar();

//get a session from Laravel application 
$session = $url_base."session";
$sessionResult = $client->get("$session",['cookies'=>$jar]);

//get JSON formatted token that was returned and type it as an array
$sessionBody = str_replace('&quot;','"',(string) $sessionResult->getBody());
$sessionToken = (array) json_decode($sessionBody);

//This is for my Laravel application route to define bucket to put image in
//depends on api being called
$uri = $url_base."{apiCategory}/{apiKey}";

//Open file as stream to upload
$body = fopen($filePath,'r');

//send POST request to upload file
$result = $client->post($uri, [
    'cookies' => $jar,
    'multipart' => [
        [
            'name'     => '_token',
            'contents' => $sessionToken['_token']
        ],
        [
            'name'     => "file",
            'contents' => $body,
            'filename' => $fileName,
            'type' => $mime
        ],
    ]
]);

On the Laravel Sever side:

...
    Route::get('/session',function()
    {
        return view('pages.session');
    });
...

resources\views\pages\session.blade.php:

{{json_encode(['_token'=>csrf_token()])}}
TwinLight's avatar

here is my snippet for laravel 5,

        $.ajax({
          method: "POST",
          headers: {'X-CSRF-TOKEN': "{{ csrf_token() }}" },
          url: "{{url('/yoururl/')}}",
          data: {'slug' : slug},
          success: function(data){
                //your actions
          },
        });
     
screenager's avatar

I was also experiencing this problem after I set the 'secure' flag to true in session.php (in order to have more secure cookies)

sameermalikrp's avatar
<form class="form-horizontal" role="form" method="POST" action="../auth/login">
{!! csrf_field() !!}
Next

Please or to participate in this conversation.