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

nolros's avatar
Level 23

Why does the Twitter Socialite Provider hate me?

// Step 1 - ALL IS GOOD AND WE ARE OFF!!

  $this->socialite->driver($provider)->redirect();

Which then starts the first part of OAuth 1.0 authentication to retrieving temporary credentials.

 public function redirect()
 {
    $this->request->getSession()->set(
   'oauth.temp', $temp = $this->server->getTemporaryCredentials()
    );

Firs part of this is great. If you run Session::get('aouth,temp ') you will see the temp credentials. The 2nd part of this method also works fine. FYI - it redirects you to Twitter auth page as promised and you end up on a twitter screen that asks for authorization.

    return new RedirectResponse($this->server->getAuthorizationUrl($temp));
 }

You then approve auth on the twitter site and more good news - it returns a valid oauth_token and oauth_verifier.

// Step 3 - YES SIR, WE HAVE A RETURN REDIRECT WITH VALID TOKEN & VERIFIER! HOUSTON WE ARE A GO FOR BURN

Then you make a call to 2nd part of the Socialite core methods to get the user credentials with a user method call:

$this->socialite->driver($provider)->user();

It begins with the user() method in AbtractProvider class in on oauth1 socialite directory.

 public function user()
 {

    if ( ! $this->hasNecessaryVerifier())

    {
   throw new \InvalidArgumentException("Invalid request. Missing OAuth verifier.");
    }

the first part i.e. the above works fine as I can verify I a have token and verifier, from teh Twitter redirect. The user mthod has a call to get token.

    $user = $this->server->getUserDetails($token = $this->getToken());

the getToken() method also in the oauth1 abstractprovider gets the temp oauth which succeeds, but not really as the temp oauth are not the original credentials.

 protected function getToken()
 {

    $temp = $this->request->getSession()->get('oauth.temp');

it is then passes the temp creditentials to getTokenCredentials() method below in server.php League\OAuth1 where it breaks. As somewhere along the path it has done a redirect and reset the temp aouth credentials. I don't know where and been pulling my hair out trying to find the source of this 2nd temp creditentials call.

 return $this->server->getTokenCredentials(
   $temp, $this->request->get('oauth_token'), $this->request->get('oauth_verifier')
    );
 }

So the temp oauth are not the same as the same as the very first socialite ->redirect() and it throws up the man-in-middle warning.

   public function getTokenCredentials(TemporaryCredentials $temporaryCredentials, $temporaryIdentifier, $verifier)
    {

        if ($temporaryIdentifier !== $temporaryCredentials->getIdentifier()) {
            throw new \InvalidArgumentException(
                "Temporary identifier passed back by server does not match that of stored temporary credentials.
                Potential man-in-the-middle."
            );
        }

Don't read below because you will never get to experience the a world full of user data yummy. Above is coach and below is first class. That said I do wonder what wonders lie in this Wonka factory of Chocolate covered twitter user data, but I will never know because it hates me

// Now, we'll store the token credentials and discard the temporary
// ones - they're irrelevant at this stage.
unset($_SESSION['temporary_credentials']);
$_SESSION['token_credentials'] = serialize($tokenCredentials);
session_write_close();

// Redirect to the user page
header("Location: http://{$_SERVER['HTTP_HOST']}/?user=user");
exit;

if (isset($_GET['user'])) {

0 likes
9 replies
winglian's avatar

If you are using Safari or Chrome, the pre-fetch/pre-render can cause a duplicate request to be sent in the background. You can get a race condition where the tokens for the pre-fetched request are the ones stored in the session causing the mis-match. Hope this helps!

1 like
Francismori7's avatar

@digitalhuman Your blog post is useless, line numbers aren't static in between versions, and besides you say prepend, prepend with?

DS's avatar

You could try to use the SocialiteProviders/Twitter Provider which I just pushed. I've used it for quite some time locally/private and never had any issues with it even though they are almost the same code wise.

Installation Instructions can be found here http://socialiteproviders.github.io/providers/twitter/.

Route::get('redirect', function () {
    return Socialite::driver('twitter')->redirect();
});

Route::get('connect', function () {
    $user = Socialite::driver('twitter')->user();

    dump($user);
});
felipemarques's avatar

Hi guys,

Because we can not extend the Twitter Provider Socialite and just apply stateless and cookie? The cookie generates a security issue? I managed to solve the TwitterProvider the problem as follows Socialite:

  1. First solution: I directly changed the /vendor/laravel/socialite/src/One/AbstractProvider.php file and let as follows:
<?php

namespace Laravel\Socialite\One;

use Illuminate\Http\Request;
use InvalidArgumentException;
use League\OAuth1\Client\Server\Server;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Laravel\Socialite\Contracts\Provider as ProviderContract;

abstract class AbstractProvider implements ProviderContract
{

  // ... above have other methods

    /**
     * Redirect the user to the authentication page for the provider.
     *
     * @editedBy Felipe Marques <contato@felipemarques.com.br>
     * @return RedirectResponse
     */
    public function redirect()
    {
        if (!$this->isStateless()) {
            $this->request->getSession()->set(
                'oauth.temp', $temp = $this->server->getTemporaryCredentials()
            );
        } else {
            $temp = $this->server->getTemporaryCredentials();
            setcookie('oauth_temp',serialize($temp));

        }

        return new RedirectResponse($this->server->getAuthorizationUrl($temp));
    }

    /**
     * Get the User instance for the authenticated user.
     *
     * @return \Laravel\Socialite\One\User
     */
    public function user()
    {
        if (! $this->hasNecessaryVerifier()) {
            throw new InvalidArgumentException('Invalid request. Missing OAuth verifier.');
        }

        $user = $this->server->getUserDetails($token = $this->getToken());

        $instance = (new User)->setRaw($user->extra)
                ->setToken($token->getIdentifier(), $token->getSecret());

        return $instance->map([
            'id' => $user->uid, 'nickname' => $user->nickname,
            'name' => $user->name, 'email' => $user->email, 'avatar' => $user->imageUrl,
        ]);
    }

    /**
     * Get the token credentials for the request.
     *
     * @editedBy Felipe Marques <contato@felipemarques.com.br>
     * @return \League\OAuth1\Client\Credentials\TokenCredentials
     */
    protected function getToken()
    {
        if (!$this->isStateless()) {
            $temp = $this->request->getSession()->get('oauth.temp');

            return $this->server->getTokenCredentials(
                $temp, $this->request->get('oauth_token'), $this->request->get('oauth_verifier')
            );
        } else {

            $temp = unserialize($_COOKIE['oauth_temp']);

            return $this->server->getTokenCredentials(
                $temp, $this->request->get('oauth_token'), $this->request->get('oauth_verifier')
            );

        }
    }

    /**
     * Determine if the request has the necessary OAuth verifier.
     *
     * @return bool
     */
    protected function hasNecessaryVerifier()
    {
        return $this->request->has('oauth_token') && $this->request->has('oauth_verifier');
    }

    /**
     * Set the request instance.
     *
     * @param  Request  $request
     * @return $this
     */
    public function setRequest(Request $request)
    {
        $this->request = $request;

        return $this;
    }

    /**
     * Indicates if the session state should be utilized.
     *
     * @editedBy Felipe Marques <contato@felipemarques.com.br>
     * @var bool
     */
    protected $stateless = false;

    /**
     * Determine if the provider is operating as stateless.
     *
     * @editedBy Felipe Marques <contato@felipemarques.com.br>
     * @return bool
     */
    protected function isStateless()
    {
        return $this->stateless;
    }

    /**
     * Indicates that the provider should operate as stateless.
     *
     * @editedBy Felipe Marques <contato@felipemarques.com.br>
     * @return $this
     */
    public function stateless()
    {
        $this->stateless = true;

        return $this;
    }
}

?>
  1. Second solution: try to extend the socialite... comming son.
martinbean's avatar

@nolros Looking at the Socialite repository, there’s a Twitter provider. You seem to have a lot of code that I wouldn’t expect in a Socialite implementation. How you tried something like the following?

class AuthController extends Controller
{
    public function getRedirect()
    {
        return Socialite::driver('twitter')->redirect();
    }

    public function getCallback()
    {
        $user = Socialite::driver('twitter')->user();
    }
}
mahmoudz's avatar

It hates me too :P

I've submitted this PR so you can now do this:

$user = Socialite::driver($provider)->userFromTokenAndSecret($oauth_token, $oauth_token_secret);
codesynt's avatar

Hello!

After all i was using the cilent id instead of the api key! That was my problem, hope this helps someone!

amanjaswalia's avatar

Hello All! I think most of us this issue resolved . But anyone test twitter or facebook login in older versions of IE in windows vista or 7 ? When i try with facebook or twitter login in windows 7 with IE11 getting NULL value from One/AbstractProvider.php -> getToken() -> $temp = $this->request->session()->get('oauth.temp') Not get value from "oauth.temp". On upper version of IE , all version of firefox and chrome working fine and get value in "oauth.temp". Please help.

Please or to participate in this conversation.