100

I'm using Laravel Socialite to add a Facebook connect button on a website. Sometimes, I've got this error on callback:

exception 'Laravel\Socialite\Two\InvalidStateException' 
in /example/vendor/laravel/socialite/src/Two/AbstractProvider.php:161

I don't know what it mean and did not found anything yet about this error. The real problem is it seems to be a random exception (don't understood why it happens). So what this error means and how to avoid it?

It seems it's not the same problem as Laravel 5 geting InvalidStateException in AbstractProvider.php, cause in my case it's random.

Community
  • 1
  • 1
rap-2-h
  • 30,204
  • 37
  • 167
  • 263
  • I think this might be the problem, http://stackoverflow.com/a/29975589/1430587 – oBo Jun 05 '15 at 07:41
  • possible duplicate of [Laravel 5 geting InvalidStateException in AbstractProvider.php](http://stackoverflow.com/questions/29629287/laravel-5-geting-invalidstateexception-in-abstractprovider-php) – paulina_glab Jun 05 '15 at 07:44
  • It's really close, but I think it's not the same problem because of the randomness – rap-2-h Jun 05 '15 at 08:58
  • 1
    I had this issue when visiting my app from different url paths e.g. if I tried logging in from www.mysite.com/ it would work, but if I visited by going to http:\\mysite.com it would have that error. – Chris Townsend Jun 05 '15 at 15:30
  • 1
    The question is whether it's really random or it just appears random (humans are pretty bad at identifying truly random phenomena). I'd start logging **everything** when this exception is thrown, to see if a pattern emerges. Given that others (@ChrisTownsend and myself, in the answer cited above) have identified this as being potentially related to a session cookie issue, I'd start there. – Kryten Jun 05 '15 at 16:07
  • Thanks! It's a good start, I'll try asap and edit my question – rap-2-h Jun 05 '15 at 16:14
  • Same here also, don't no the reasons – Marwan Nov 03 '17 at 16:41

28 Answers28

118

I ran into this issue last night and solve it with the following solution.

More information on my issue, I've got

InvalidStateException in AbstractProvider.php line 182

in the function handleProviderCallback() when it re-direct back from Facebook login. It seems to be the same as your issue.

Furthermore I found my issue occurs when I open my site without www. When I open my site with www.mysite.com - no problem. At first I think my issue is random until I've got the clue by Chris Townsend's reply to the question - Thank you very much.

The Solution

  1. Go to your www root, check the laravel file config/session.php
  2. Check session Session Cookie Domain The default configuration is 'domain' => null, I made a change to 'domain' => 'mysite.com'.
  3. After 'php artisan cache:clear' and 'composer dump-autoload', I can login with no issue from both www.mysite.com and mysite.com

Be sure to delete your cookies from browser when testing it after these modifications are done. Old cookies can still produce problems.

Mladen Janjetovic
  • 13,844
  • 8
  • 72
  • 82
Chaochana
  • 1,312
  • 1
  • 9
  • 8
  • 3
    Correct, but for people working on localhost and Chrome. Keep in mind that Chrome does now set cookies for for localhost, therefore problem will remain, to solve add valid (one with dot inside) domain name to hosts file and then change laravel config files accordingly. – ggat Dec 27 '15 at 18:49
  • 2
    What should I write exactly for domain in case of localhost? – Nil Sep 20 '16 at 10:33
  • I have my problem solved, but according to reports, it still occures to users of my website. How can I resolve. I tried renaming the cookie, but still same. I don't have any problems but cant say the same about the users – naneri Oct 09 '16 at 12:52
  • 2
    It is needed to change both 'domain' and 'cookie' values in config/session.php. Otherwise user will get unexpected login issue. please see https://stackoverflow.com/questions/33260856/laravel-authlogin-doesnt-persist-after-change-domain-in-session/35694300#35694300 – ruwan800 Oct 14 '17 at 20:01
  • 2
    I just redirected www to non-www in `.htaccess`. I used [this article](https://simonecarletti.com/blog/2016/08/redirect-domain-http-https-www-apache/) that also redirects HTTP to HTTPS. – totymedli Mar 04 '18 at 08:20
  • I just changed `APP_URL` in the .env file. – Malinda Sep 12 '18 at 07:40
  • Worked like a charm, Kinda odd that the SESSION_DOMAIN is not part of the default .enf config – Adam Patterson Jun 14 '19 at 20:49
  • 1
    **THIS IS SO IMPORTANT!!** I BROKE my production website after this change! make sure that you update the `cookie` also, otherwise, your session won't be saved anymore! – shamaseen Apr 09 '21 at 23:17
  • ´php artisan cache:clear´ was enough for me – marimaf Oct 04 '22 at 14:29
106

Resolved :

Socialite::driver('google')->stateless()->user()
Nazik
  • 8,696
  • 27
  • 77
  • 123
Nguyen Phuong
  • 1,211
  • 1
  • 10
  • 6
  • When I did this the user wasn't logged in after the redirect. I used auth()->login($user); etc... – cmac Oct 21 '16 at 21:09
  • 9
    Be sure to add `stateless()` to your redirect line as well or you may have trouble logging in after redirect. `Socialite::driver('google')->stateless()->redirect() ` – HelloSpeakman Feb 01 '18 at 14:49
  • Work for me, in case when i have to login from one subdomain and redirect back to another subdomain. – Rahul Sharma Feb 09 '18 at 07:28
  • Where should I insert `Socialite::driver('google')->stateless()->user()`? In what file? Thanks. – Eem Jee Feb 07 '19 at 03:30
  • 4
    What does it do, why do you need it? – digout Nov 08 '20 at 15:43
  • 2
    Going `stateless()` is not without potential cost to security. Read about an unlikely but real attack scenario here: https://stackoverflow.com/a/35988614 Maybe it's OK for you and your users, maybe it's not. – Jan Żankowski Feb 11 '21 at 22:53
20

tl;dr

If you need to read a given parameter state returned by a thirdparty service, you can set Socialite to avoid this checking with the stateless method:

   Socialite::driver($provider)->stateless();

I think Socialite is already prepared to avoid this issue.

https://github.com/laravel/socialite/blob/2.0/src/Two/AbstractProvider.php#L77

 /**
 * Indicates if the session state should be utilized.
 *
 * @var bool
 */
protected $stateless = false;

https://github.com/laravel/socialite/blob/2.0/src/Two/AbstractProvider.php#L374

/**
 * Indicates that the provider should operate as stateless.
 *
 * @return $this
 */
public function stateless()
{
    $this->stateless = true;
    return $this;
}

https://github.com/laravel/socialite/blob/2.0/src/Two/AbstractProvider.php#L222

/**
 * Determine if the current request / session has a mismatching "state".
 *
 * @return bool
 */
protected function hasInvalidState()
{
    if ($this->isStateless()) {
        return false; // <--------
    }
    $state = $this->request->getSession()->pull('state');
    return ! (strlen($state) > 0 && $this->request->input('state') === $state);
}

For instance, state is very useful to pass data throught google:

Parameter: state (Any string)
Provides any state that might be useful to your application upon receipt of the response. The Google Authorization Server round-trips this parameter, so your application receives the same value it sent. Possible uses include redirecting the user to the correct resource in your site, and cross-site-request-forgery mitigations.

ref: https://developers.google.com/identity/protocols/OAuth2UserAgent#overview

Igor Parra
  • 10,214
  • 10
  • 69
  • 101
18

There are 2 major "gotchas" that none of the existing answers address.

  1. Sometimes InvalidStateException is a red herring and the true root cause is some other bug. It took me ~12 hours one time to realize that I hadn't added a new field to the $fillable array in the model.
  2. Unless you disable session state verification (as other answers here seem to want you to do but not everyone will want to do), $provider->user() can only be called once per request because the inside of that function calls hasInvalidState(), which then removes the 'state' entry from the session. It took me hours to realize that I happened to be calling $provider->user() multiple times, when I should have called it just once and saved the result to a variable.
Ryan
  • 22,332
  • 31
  • 176
  • 357
9

I was only experiencing this error when logging in via mobile web with the facebook app instead of facebook in browser. The facebook app uses the facebook browser after login instead of your current browser, so is unaware of previous state.

try {
    $socialite = Socialite::driver($provider)->user();
} catch (InvalidStateException $e) {
    $socialite = Socialite::driver($provider)->stateless()->user();
}
makhag
  • 101
  • 1
  • 2
9

October 2020

For me, I had

…\vendor\laravel\socialite\src\Two\AbstractProvider.php209

So I converted my code from

$user = Socialite::driver('facebook')->user();

to

$user = Socialite::driver('facebook')->stateless()->user();

I didn't have to run any cache clearing, I did delete the cookies though but I'm not sure you have to.

Oussema Miled
  • 528
  • 6
  • 13
  • 3
    Can you explain why the `stateless()` resolves this issue? It worked for me too but I want to know why it was needed and why it fixes it. Thank you. – CodeConnoisseur Nov 17 '21 at 16:08
6

I've got same happen only when I open my web on mobile and open the dialog by facebook application on my phone.

I think: This happen because open facebook app to get response from Facebook API make we lost some cookie. it's become stateless. Then I just use the option that socialite are already made to avoid stateless request.

$user = Socialite::driver($provider)->stateless()->user();

It's worked to me. hope it help you

Quân Hoàng
  • 371
  • 3
  • 9
5

2020/04

If this issue appeared for you around Feb. 2020, there is a good chance it has to do with Google Chrome version 80+ which was released in the beginning of Feb. 2020. I am not going to pretend I understand the issue in it's entirety, but in short Google Chrome treats cookies now as SameSite=Lax by default if no SameSite attribute is specified.

If your app depends on working cross-site cookies, you will need to add "SameSite=None; Secure" to your cookies. In Laravel 5.5+ you can achieve that with two changes in the session configuration:

config/session.php

'secure' => env('SESSION_SECURE_COOKIE', true), // or set it to true in your .env file

...

'same_site' => "none",

The "none" value was apparently not supported in earlier Laravel versions. But it is now, if this produces a weird error check /vendor/symfony/http-foundation/Cookie.php and make sure there is a SAMESITE_NONE constant. If it doesn't exist you probably need to upgrade your Laravel version.

Further reading:

mwallisch
  • 1,751
  • 2
  • 21
  • 29
4

I had the same problem and I just cleared the cache to solve this problem. I just ran this command and started the process again.

php artisan cache:clear

I hope this answer may help someone.

AboElnouR
  • 281
  • 3
  • 14
3

Also check access right on your storage/framework/sessions folder.

In my case, since this folder is empty in new Laravel project, it has been left out during initially commit to the GIT repository. Afterwards I created it manually on production server, but obviously with the wrong access rights, hence it was not writable for the session driver (when set to 'file').

Greegus
  • 406
  • 1
  • 5
  • 14
3

Got the Solution - Update November 2018

public function redirectToGoogle(Request $request)
{
    /**
     * @var GoogleProvider $googleDriver
     */
    $googleDriver = Socialite::driver("google");
    return $googleDriver->redirect();
}

public function fromGoogle(Request $request)
{
    try {
/*
Solution Starts ----
*/
        if (empty($_GET)) {
            $t = parse_url($_SERVER['REQUEST_URI'], PHP_URL_QUERY);
            parse_str($t, $output);
            foreach ($output as $key => $value) {
                $request->query->set($key, $value);
            }
        }
/*
Solution Ends ----
*/
        /**
         * @var GoogleProvider $googleDriver
         */
        $googleDriver = Socialite::driver("google");
        print_r($googleDriver->user());
    } catch (\Exception $e) {
        print_r($e->getMessage());
    }
Tarinder
  • 51
  • 3
3

i have faced the same issue its just because of using 127.0.0.1:8000/ instead of http://localhost:8000/

Dhinesh Kumar
  • 119
  • 1
  • 6
2

In my case it was caused by missing parameters in $fillable array in User class. When i added all missing parameters, it started to work properly..

Jan Kotas
  • 71
  • 1
  • 3
2

Laravel: 7.10.3

PHP: 7.3.15

I was having this issue too. Somehow the proposed solutions didn't help me getting the problem fixed.

After spending a lot of time trying to fix my code, i thought this also could have to do something with my php-fpm -> nginx setup.

After changing my nginx configuration loging in via Facebook now works.

INCORRET CONFIGURATION:

location ~ \.(php|phar)(/.*)?$ {
    fastcgi_split_path_info ^(.+\.(?:php|phar))(/.*)$;
    fastcgi_intercept_errors on;
    fastcgi_index  index.php;
    include        fastcgi_params;
    fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
    fastcgi_param  PATH_INFO $fastcgi_path_info;
    fastcgi_pass   unix:/var/run/php-fpm/www.sock;
}

location / {
   try_files $uri $uri/ /index.php;
}

CORRECT CONFIGURATION

location / {
    try_files $uri $uri/ /index.php?$query_string;
}

location ~ \.php$ {
    try_files $uri =404;
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    fastcgi_pass unix:/var/run/php-fpm/www.sock;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;
}
Arthur
  • 921
  • 3
  • 13
  • 25
1

I fixed this just disabling the SESSION DRIVER as database... file driver worked fine for me after hours trying to fix this s...

insign
  • 5,353
  • 1
  • 38
  • 35
1

I had a similar issue, I've got

InvalidStateException in AbstractProvider.php line 182

in the function handleProviderCallback() when it re-directs back from Facebook login. It seems to be the same as your issue.

Furthermore I found my issue occurs when I open my site without www. When I open my site with www.mysite.com - no problem. At first I think my issue is random until I've got the clue by Chris Townsend's reply to the question.

The Solution

Go to your www root, check the laravel file config/session.php. Check session Session Cookie Domain. The default configuration is 

'domain' => null,

I made a change to 

'domain' => 'mysite.com' 

After php artisan cache:clear and composer dump-autoload, I can login with no issue from both www.mysite.com and mysite.com

Be sure to delete your cookies from browser when testing it after these modifications are done. Old cookies can still produce problems.

Greenonline
  • 1,330
  • 8
  • 23
  • 31
1

Laravel 6.16.0
php 7.4.2

I came across this exact issue. Turns out I recently changed same_site to strict and socialite was throwing InvalidStateException exception. Then I changed it to back to null and all worked fine.

/*
    |--------------------------------------------------------------------------
    | Same-Site Cookies
    |--------------------------------------------------------------------------
    |
    | This option determines how your cookies behave when cross-site requests
    | take place, and can be used to mitigate CSRF attacks. By default, we
    | do not enable this as other CSRF protection services are in place.
    |
    | Supported: "lax", "strict"
    |
    */

    'same_site' => null,
Digvijay
  • 7,836
  • 3
  • 32
  • 53
1

In my scenario, I had two Laravel applications running on localhost, one implementing passport, and on utilizing socialite to authenticate against the passport application. I had forgotten to set the APP_NAME in .env, so each application was writing the same lavarel_session cookie, so the socialite app wasn't able to pull the state value from the session, since the other app had stomped on the cookie.

Ensure that you set the APP_NAME value in .env when setting up your apps if you have them running on the same domain and are consuming your own provider.

Vigs
  • 1,286
  • 3
  • 13
  • 30
1

Finally i solved by :

Redirect URL in .env file should be the same URL in google developer account

double check on your redirects urls .

Abd Abughazaleh
  • 4,615
  • 3
  • 44
  • 53
0

If you still need help you can use my code, it works for me. You just need to create two routes and update the users table. Don't forget to make password nullable, since you won't get one from the facebook users The code in my controller:

public function redirectToProvider()
{
    return Socialize::with('facebook')->redirect();
}

public function handleProviderCallback(User $user)
{
    $money = Socialize::with('facebook')->user();

    if(User::where('email', '=', $money->email)->first()){
    $checkUser = User::where('email', '=', $money->email)->first();
    Auth::login($checkUser);
    return redirect('home');
     } 

    $user->facebook_id = $money->getId();
    $user->name = $money->getName();
    $user->email = $money->getEmail();
    $user->avatar = $money->getAvatar();
    $user->save();

    Auth::login($user);
    return redirect('home');

}
0

this solved it for me
$request->session()->put('state',Str::random(40)); $user = Socialite::driver('github')->stateless()->user();

lacasera
  • 9
  • 4
0

On your Controller within the callback() method

$user = $service->createOrGetUser(Socialite::driver('facebook')->user());

$user = $service->createOrGetUser(Socialite::driver('facebook')->stateless()->user());

0

I stacked on this two day and changing 'driver' => env('SESSION_DRIVER', 'file')to 'driver' => env('SESSION_DRIVER', 'cookie') worked for me

Jared Forth
  • 1,577
  • 6
  • 17
  • 32
0

For me the solution was to set APP_URL to http://localhost:8000 instead of http://127.0.0.1:8000 (presuming that you run your server on the 8000 port).

Then, clean config and cache:

  • php artisan config:clear
  • php artisan cache:clear

Clear cookies (or run in incognito mode)

Since facebook allow localhost redirect by default, you don't have to whitelist the url in the fb app.

ml59
  • 1,495
  • 1
  • 9
  • 10
0

This is a session-related issue.

If you're using an SSH tunneling service such as ngrok.com then you should use the exact same URL as the social redirect URL, otherwise, you need to modify the domain in the session.php file (which is a bad idea IMO).

Ahmad
  • 808
  • 9
  • 14
0
$user = Socialite::driver('github')->stateless()->user();
Md. Ali Rabbi
  • 11
  • 1
  • 3
-2

This issue has nothing to do with a lot of the solutions above, is rather as simple as changing your callback URL from 'http://localhost:8000/callback/twitter to http://127.0.0.1:8000/callback/twitter in your config/services.php and on your twitter app set up on your twitter application.

the http://localhost in the URL is the issue, replace with http://127.0.0.1

Adépòjù Olúwáségun
  • 3,297
  • 1
  • 18
  • 27
-5

I want to share you my solution . I go to my AbstractProvider.php file and in the line of problem

public function user()
{
    if ($this->hasInvalidState()) {
        throw new InvalidStateException;
    }

    // ...
}

I stop the throw new InvalidStateException and call the redirect function like that:

public function user()
{
    if ($this->hasInvalidState()) {
        $this->redirect();
        // throw new InvalidStateException;
    }

    // ...
}
Damaged Organic
  • 8,175
  • 6
  • 58
  • 84
  • This just launches the auth in an infinite loop, right ? `redirect()` is for the first part of the process, whereas `user()` is the second part... – Kaktus Jun 20 '17 at 20:47