Search code examples
phpandroidfacebookoauth-2.0

Issue to migrate from php-graph-sdk to oauth2-facebook library for Facebook Login with a mobile app


I am trying to migrate from php-graph-sdk to oauth2-facebook as the first one does not seem to be maintained anymore (no activity on github for 3 years), and the second one seemed easy to use.

For a full web scenario where the user clicks on a Facebook Login button and gets authenticated, everything works fine: when logged out, the library allows me to generate a url for the Login with Facebook button, and the callback allows to generate a token based on the code received.

For a mobile <--> web scenario, things start to break: I am using the Facebook Android and iOS SDK to get an accessToken that I pass to my php script. Then I try to use this accessToken to retrieve the user profile:

        require_once "lib/oauth2/autoload.php";
        $providerFacebook = new \League\OAuth2\Client\Provider\Facebook([
            'clientId'          => 'xxxxx',
            'clientSecret'      => 'xxxxx',
            'redirectUri'       => 'https://www.foobar.com/login.php',
            'graphApiVersion'   => 'v3.2',
        ]);
        
        // Try to look up user profile data with the access token
        try
        {
            $facebook_user = $providerFacebook->getResourceOwner($_POST["accessToken"]); // <-- problem here
            // print_r($facebook_user->toArray());
            $fb_user = [
                "id" => $facebook_user->getId(),
                "name" => $facebook_user->getName(),
                "email" => $facebook_user->getEmail(),
                "picture_url" => $facebook_user->getPictureUrl(),
            ];
        }
        catch( \Exception $e )
        {
            // Failed to get user details
            // echo "<!-- ERROR: ".$e->getMessage()." --> ";
        }

However this does not work. I could isolate that the following command crash the script (without any error description)

$facebook_user = $providerFacebook->getResourceOwner($_POST["accessToken"]);

The frustrating thing is that the (almost) same code works well if the login starts from the web:

        require_once "lib/oauth2/autoload.php";
        $providerFacebook = new \League\OAuth2\Client\Provider\Facebook([
            'clientId'          => 'xxxxx',
            'clientSecret'      => 'xxxxx',
            'redirectUri'       => 'https://www.foobar.com/login.php',
            'graphApiVersion'   => 'v3.2',
        ]);

        // Try to get an access token (using the authorization code grant)
        try {
            $token = $provider->getAccessToken('authorization_code', [
                'code' => $_GET['code']
            ]);
        } catch (\Exception $e) {

            // Failed to get user details
            echo $e->getMessage();
            exit('Oh my god...');
        }
        
        // Try to look up user profile data with the access token
        try
        {
            $facebook_user = $providerFacebook->getResourceOwner($token); // OK!
            // print_r($facebook_user->toArray());
            $fb_user = [
                "id" => $facebook_user->getId(),
                "name" => $facebook_user->getName(),
                "email" => $facebook_user->getEmail(),
                "picture_url" => $facebook_user->getPictureUrl(),
            ];
        }
        catch( \Exception $e )
        {
            // Failed to get user details
            // echo "<!-- ERROR: ".$e->getMessage()." --> ";
        }

As a reference, my legacy code that works well in both scenarios is the following:

        // Facebook
        require_once "lib/Facebook/autoload.php";

        $fb = new Facebook\Facebook([
            'app_id' => 'xxxxx', // Replace {app-id} with your app id
            'app_secret' => 'xxxxx',
            'default_graph_version' => 'v3.2',
        ]);
        
        $fb_res = $fb->get('/me?fields=id,name,email,picture.width(600)', $_POST["accessToken"]);
        $fb_graph = $fb_res->getGraphUser();
        $fb_avatar = json_decode($fb_graph["picture"]);
        
        $fb_user = [
            "id" => $fb_graph["id"],
            "name" => $fb_graph["name"],
            "email" => $fb_graph["email"],
            "picture_url" => $fb_avatar->url,
        ];

Solution

  • $facebook_user = $providerFacebook->getResourceOwner($_POST["accessToken"]);
    

    The getResourceOwner method expects an AccessToken instance as parameter, you can not just pass the token value itself as text.

    The constructor for \League\OAuth2\Client\Token\AccessToken takes an array of parameters, providing one containing access_token should be sufficient here.

    $token = new \League\OAuth2\Client\Token\AccessToken(['access_token'=>$_POST["accessToken"]);
    $facebook_user = $providerFacebook->getResourceOwner($token);