1

I'm using Social Login Extension in Magento 226 trying to login with Google but it's showing below error.

Ooophs, we got an error: User profile request failed! Google returned an invalid response:stdClass::__set_state(array( 'error' => stdClass::__set_state(array( 'code' => 403, 'message' => 'Legacy People API has not been used in project 36088930720 before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/legacypeople.googleapis.com/overview?project=36088930720 then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.', 'status' => 'PERMISSION_DENIED', 'details' => array ( 0 => stdClass::__set_state(array( '@type' => 'type.googleapis.com/google.rpc.Help', 'links' => array ( 0 => stdClass::__set_state(array( 'description' => 'Google developers console API activation', 'url' => 'https://console.developers.google.com/apis/api/legacypeople.googleapis.com/overview?project=36088930720', )), ), )), ), )), ))

Sometimes Error Changes to below error,

Ooophs, we got an error: User profile request failed! Google returned an invalid response:stdClass::__set_state(array( 'error' => stdClass::__set_state(array( 'code' => 401, 'message' => 'Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.', 'status' => 'UNAUTHENTICATED', )), ))

Things I've tried but didn't work,

  • I've tried visiting URL that suggested in Error but it shows URL Error
  • Creating new Credentials.
  • Tried enabling google+, contacts, script APIs.

Can anyone tell me how to resolve this error?

1 Answer 1

3

Finally, I have found an answer by myself after some digging. I did some changes to the Hybrid Library file. Make sure you enable Google People API as Google+ APIs have been Shutdown.

Before changes, the code was as followed,

Hybrid/Providers/Google.php

<?php

/* !
 * HybridAuth
 * http://hybridauth.sourceforge.net | http://github.com/hybridauth/hybridauth
 * (c) 2009-2015, HybridAuth authors | http://hybridauth.sourceforge.net/licenses.html
 */

/**
 * Hybrid_Providers_Google provider adapter based on OAuth2 protocol
 *
 * http://hybridauth.sourceforge.net/userguide/IDProvider_info_Google.html
 */
class Hybrid_Providers_Google extends Hybrid_Provider_Model_OAuth2 {

    /**
     * > more infos on google APIs: http://developer.google.com (official site)
     * or here: http://discovery-check.appspot.com/ (unofficial but up to date)
     * default permissions
     * {@inheritdoc}
     */
    public $scope = "https://www.googleapis.com/auth/plus.login https://www.googleapis.com/auth/plus.profile.emails.read https://www.google.com/m8/feeds/";

    /**
     * {@inheritdoc}
     */
    function initialize() {
        parent::initialize();

        // Provider api end-points
        $this->api->authorize_url = "https://accounts.google.com/o/oauth2/auth";
        $this->api->token_url = "https://accounts.google.com/o/oauth2/token";
        $this->api->token_info_url = "https://www.googleapis.com/oauth2/v2/tokeninfo";

        // Google POST methods require an access_token in the header
        $this->api->curl_header = array("Authorization: OAuth " . $this->api->access_token);

        // Override the redirect uri when it's set in the config parameters. This way we prevent
        // redirect uri mismatches when authenticating with Google.
        if (isset($this->config['redirect_uri']) && !empty($this->config['redirect_uri'])) {
            $this->api->redirect_uri = $this->config['redirect_uri'];
        }
    }

    /**
     * {@inheritdoc}
     */
    function loginBegin() {
        $parameters = array("scope" => $this->scope, "access_type" => "offline");
        $optionals = array("scope", "access_type", "redirect_uri", "approval_prompt", "hd", "state");

        foreach ($optionals as $parameter) {
            if (isset($this->config[$parameter]) && !empty($this->config[$parameter])) {
                $parameters[$parameter] = $this->config[$parameter];
            }
            if (isset($this->config["scope"]) && !empty($this->config["scope"])) {
                $this->scope = $this->config["scope"];
            }
        }

        if (isset($this->config['force']) && $this->config['force'] === true) {
            $parameters['approval_prompt'] = 'force';
        }

        Hybrid_Auth::redirect($this->api->authorizeUrl($parameters));
    }

    /**
     * {@inheritdoc}
     */
    function getUserProfile() {
        // refresh tokens if needed
        $this->refreshToken();

        // ask google api for user infos
        if (strpos($this->scope, '/auth/plus.profile.emails.read') !== false) {
            $verified = $this->api->api("https://www.googleapis.com/plus/v1/people/me");

            if (!isset($verified->id) || isset($verified->error))
                $verified = new stdClass();
        } else {
            $verified = $this->api->api("https://www.googleapis.com/plus/v1/people/me/openIdConnect");

            if (!isset($verified->sub) || isset($verified->error))
                $verified = new stdClass();
        }

        $response = $this->api->api("https://www.googleapis.com/plus/v1/people/me");
        if (!isset($response->id) || isset($response->error)) {
            throw new Exception("User profile request failed! {$this->providerId} returned an invalid response:" . Hybrid_Logger::dumpData( $response ), 6);
        }

        $this->user->profile->identifier = (property_exists($verified, 'id')) ? $verified->id : ((property_exists($response, 'id')) ? $response->id : "");
        $this->user->profile->firstName = (property_exists($response, 'name')) ? $response->name->givenName : "";
        $this->user->profile->lastName = (property_exists($response, 'name')) ? $response->name->familyName : "";
        $this->user->profile->displayName = (property_exists($response, 'displayName')) ? $response->displayName : "";
        $this->user->profile->photoURL = (property_exists($response, 'image')) ? ((property_exists($response->image, 'url')) ? substr($response->image->url, 0, -2) . "200" : '') : '';
        $this->user->profile->profileURL = (property_exists($response, 'url')) ? $response->url : "";
        $this->user->profile->description = (property_exists($response, 'aboutMe')) ? $response->aboutMe : "";
        $this->user->profile->gender = (property_exists($response, 'gender')) ? $response->gender : "";
        $this->user->profile->language = (property_exists($response, 'locale')) ? $response->locale : ((property_exists($verified, 'locale')) ? $verified->locale : "");
        $this->user->profile->email = (property_exists($response, 'email')) ? $response->email : ((property_exists($verified, 'email')) ? $verified->email : "");
        $this->user->profile->emailVerified = (property_exists($verified, 'email')) ? $verified->email : "";
        if (property_exists($response, 'emails')) {
            if (count($response->emails) == 1) {
                $this->user->profile->email = $response->emails[0]->value;
            } else {
                foreach ($response->emails as $email) {
                    if ($email->type == 'account') {
                        $this->user->profile->email = $email->value;
                        break;
                    }
                }
            }
            if (property_exists($verified, 'emails')) {
                if (count($verified->emails) == 1) {
                    $this->user->profile->emailVerified = $verified->emails[0]->value;
                } else {
                    foreach ($verified->emails as $email) {
                        if ($email->type == 'account') {
                            $this->user->profile->emailVerified = $email->value;
                            break;
                        }
                    }
                }
            }
        }
        $this->user->profile->phone = (property_exists($response, 'phone')) ? $response->phone : "";
        $this->user->profile->country = (property_exists($response, 'country')) ? $response->country : "";
        $this->user->profile->region = (property_exists($response, 'region')) ? $response->region : "";
        $this->user->profile->zip = (property_exists($response, 'zip')) ? $response->zip : "";
        if (property_exists($response, 'placesLived')) {
            $this->user->profile->city = "";
            $this->user->profile->address = "";
            foreach ($response->placesLived as $c) {
                if (property_exists($c, 'primary')) {
                    if ($c->primary == true) {
                        $this->user->profile->address = $c->value;
                        $this->user->profile->city = $c->value;
                        break;
                    }
                } else {
                    if (property_exists($c, 'value')) {
                        $this->user->profile->address = $c->value;
                        $this->user->profile->city = $c->value;
                    }
                }
            }
        }

        // google API returns multiple urls, but a "website" only if it is verified
        // see http://support.google.com/plus/answer/1713826?hl=en
        if (property_exists($response, 'urls')) {
            foreach ($response->urls as $u) {
                if (property_exists($u, 'primary') && $u->primary == true)
                    $this->user->profile->webSiteURL = $u->value;
            }
        } else {
            $this->user->profile->webSiteURL = '';
        }
        // google API returns age ranges min and/or max as of https://developers.google.com/+/web/api/rest/latest/people#resource
        if (property_exists($response, 'ageRange')) {
            if (property_exists($response->ageRange, 'min') && property_exists($response->ageRange, 'max')) {
                $this->user->profile->age = $response->ageRange->min . ' - ' . $response->ageRange->max;
            } else {
                if (property_exists($response->ageRange, 'min')) {
                    $this->user->profile->age = '>= ' . $response->ageRange->min;
                } else {
                    if (property_exists($response->ageRange, 'max')) {
                        $this->user->profile->age = '<= ' . $response->ageRange->max;
                    } else {
                        $this->user->profile->age = '';
                    }
                }
            }
        } else {
            $this->user->profile->age = '';
        }
        // google API returns birthdays only if a user set 'show in my account'
        if (property_exists($response, 'birthday')) {
            list($birthday_year, $birthday_month, $birthday_day) = explode('-', $response->birthday);

            $this->user->profile->birthDay = (int) $birthday_day;
            $this->user->profile->birthMonth = (int) $birthday_month;
            $this->user->profile->birthYear = (int) $birthday_year;
        } else {
            $this->user->profile->birthDay = 0;
            $this->user->profile->birthMonth = 0;
            $this->user->profile->birthYear = 0;
        }

        return $this->user->profile;
    }

    /**
     * {@inheritdoc}
     */
    function getUserContacts() {
        // refresh tokens if needed
        $this->refreshToken();
        
        $contacts = array();
        if (!isset($this->config['contacts_param'])) {
            $this->config['contacts_param'] = array("max-results" => 500);
        }
        
        // Google Gmail and Android contacts
        if (strpos($this->scope, '/m8/feeds/') !== false) {
            
            $response = $this->api->api("https://www.google.com/m8/feeds/contacts/default/full?"
                    . http_build_query(array_merge(array('alt' => 'json'), $this->config['contacts_param'])));
            
            if (!$response) {
                return array();
            }
            
            if (isset($response->feed->entry)) {
                foreach ($response->feed->entry as $idx => $entry) {
                    $uc = new Hybrid_User_Contact();
                    $uc->email = isset($entry->{'gd$email'}[0]->address) ? (string) $entry->{'gd$email'}[0]->address : '';
                    $uc->displayName = isset($entry->title->{'$t'}) ? (string) $entry->title->{'$t'} : '';
                    $uc->identifier = ($uc->email != '') ? $uc->email : '';
                    $uc->description = '';
                    if (property_exists($entry, 'link')) {
                        /**
                         * sign links with access_token
                         */
                        if (is_array($entry->link)) {
                            foreach ($entry->link as $l) {
                                if (property_exists($l, 'gd$etag') && $l->type == "image/*") {
                                    $uc->photoURL = $this->addUrlParam($l->href, array('access_token' => $this->api->access_token));
                                } else if ($l->type == "self") {
                                    $uc->profileURL = $this->addUrlParam($l->href, array('access_token' => $this->api->access_token));
                                }
                            }
                        }
                    } else {
                        $uc->profileURL = '';
                    }
                    if (property_exists($response, 'website')) {
                        if (is_array($response->website)) {
                            foreach ($response->website as $w) {
                                if ($w->primary == true)
                                    $uc->webSiteURL = $w->value;
                            }
                        } else {
                            $uc->webSiteURL = $response->website->value;
                        }
                    } else {
                        $uc->webSiteURL = '';
                    }
                    
                    $contacts[] = $uc;
                }
            }
        }
        
        // Google social contacts
        if (strpos($this->scope, '/auth/plus.login') !== false) {
            
            $response = $this->api->api("https://www.googleapis.com/plus/v1/people/me/people/visible?"
                    . http_build_query($this->config['contacts_param']));
            
            if (!$response) {
                return array();
            }
            
            foreach ($response->items as $idx => $item) {
                $uc = new Hybrid_User_Contact();
                $uc->email = (property_exists($item, 'email')) ? $item->email : '';
                $uc->displayName = (property_exists($item, 'displayName')) ? $item->displayName : '';
                $uc->identifier = (property_exists($item, 'id')) ? $item->id : '';
                
                $uc->description = (property_exists($item, 'objectType')) ? $item->objectType : '';
                $uc->photoURL = (property_exists($item, 'image')) ? ((property_exists($item->image, 'url')) ? $item->image->url : '') : '';
                $uc->profileURL = (property_exists($item, 'url')) ? $item->url : '';
                $uc->webSiteURL = '';
                
                $contacts[] = $uc;
            }
        }
        
        return $contacts;
    }
    
    /**
     * Add query parameters to the $url
     *
     * @param string $url    URL
     * @param array  $params Parameters to add
     * @return string
     */
    function addUrlParam($url, array $params){      
        $query = parse_url($url, PHP_URL_QUERY);

        // Returns the URL string with new parameters
        if ($query) {
            $url .= '&' . http_build_query($params);
        } else {
            $url .= '?' . http_build_query($params);
        }
        return $url;
    }

}

After the changes, which is working code as followed,

Hybrid/Providers/Google.php

<?php

/* !
 * HybridAuth
 * http://hybridauth.sourceforge.net | http://github.com/hybridauth/hybridauth
 * (c) 2009-2015, HybridAuth authors | http://hybridauth.sourceforge.net/licenses.html
 */

/**
 * Hybrid_Providers_Google provider adapter based on OAuth2 protocol
 *
 * http://hybridauth.sourceforge.net/userguide/IDProvider_info_Google.html
 */
class Hybrid_Providers_Google extends Hybrid_Provider_Model_OAuth2 {

    /**
     * > more infos on google APIs: http://developer.google.com (official site)
     * or here: http://discovery-check.appspot.com/ (unofficial but up to date)
     * default permissions
     * {@inheritdoc}
     */
    public $scope = "https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email https://www.google.com/m8/feeds/";

    /**
     * {@inheritdoc}
     */
    function initialize() {
        parent::initialize();

        // Provider api end-points
        $this->api->authorize_url = "https://accounts.google.com/o/oauth2/auth";
        $this->api->token_url = "https://accounts.google.com/o/oauth2/token";
        $this->api->token_info_url = "https://www.googleapis.com/oauth2/v2/tokeninfo";

        // Google POST methods require an access_token in the header
        $this->api->curl_header = array("Authorization: OAuth " . $this->api->access_token);

        // Override the redirect uri when it's set in the config parameters. This way we prevent
        // redirect uri mismatches when authenticating with Google.
        if (isset($this->config['redirect_uri']) && !empty($this->config['redirect_uri'])) {
            $this->api->redirect_uri = $this->config['redirect_uri'];
        }
    }

    /**
     * {@inheritdoc}
     */
    function loginBegin() {
        $parameters = array("scope" => $this->scope, "access_type" => "offline");
        $optionals = array("scope", "access_type", "redirect_uri", "approval_prompt", "hd", "state");

        foreach ($optionals as $parameter) {
            if (isset($this->config[$parameter]) && !empty($this->config[$parameter])) {
                $parameters[$parameter] = $this->config[$parameter];
            }
            if (isset($this->config["scope"]) && !empty($this->config["scope"])) {
                $this->scope = $this->config["scope"];
            }
        }

        if (isset($this->config['force']) && $this->config['force'] === true) {
            $parameters['approval_prompt'] = 'force';
        }

        Hybrid_Auth::redirect($this->api->authorizeUrl($parameters));
    }

    /**
     * {@inheritdoc}
     */
    function getUserProfile() {
        // refresh tokens if needed
        $this->refreshToken();

        $response = $this->api->api("https://www.googleapis.com/oauth2/v3/userinfo");
        if (!isset($response->sub) || isset($response->error)) {
            throw new Exception("User profile request failed! {$this->providerId} returned an invalid response:" . Hybrid_Logger::dumpData( $response ), 6);
        }

        $this->user->profile->identifier = (property_exists($response, 'sub')) ? $response->sub : "";
        $this->user->profile->firstName = (property_exists($response, 'given_name')) ? $response->given_name : "";
        $this->user->profile->lastName = (property_exists($response, 'family_name')) ? $response->family_name : "";
        $this->user->profile->displayName = (property_exists($response, 'name')) ? $response->name : "";
        $this->user->profile->photoURL = (property_exists($response, 'picture')) ? $response->picture : "";
        $this->user->profile->profileURL = (property_exists($response, 'profile')) ? $response->profile : "";
        $this->user->profile->gender = (property_exists($response, 'gender')) ? $response->gender : "";
        $this->user->profile->language = (property_exists($response, 'locale')) ? $response->locale : "";
        $this->user->profile->email = (property_exists($response, 'email')) ? $response->email : "";
        $this->user->profile->emailVerified = (property_exists($response, 'email_verified')) ? ($response->email_verified === true || $response->email_verified === 1 ? $response->email : "") : "";

        return $this->user->profile;
    }

    /**
     * {@inheritdoc}
     */
    function getUserContacts() {
        // refresh tokens if needed
        $this->refreshToken();
        
        $contacts = array();
        if (!isset($this->config['contacts_param'])) {
            $this->config['contacts_param'] = array("max-results" => 500);
        }
        
        // Google Gmail and Android contacts
        if (strpos($this->scope, '/m8/feeds/') !== false) {
            
            $response = $this->api->api("https://www.google.com/m8/feeds/contacts/default/full?"
                    . http_build_query(array_merge(array('alt' => 'json'), $this->config['contacts_param'])));
            
            if (!$response) {
                return array();
            }
            
            if (isset($response->feed->entry)) {
                foreach ($response->feed->entry as $idx => $entry) {
                    $uc = new Hybrid_User_Contact();
                    $uc->email = isset($entry->{'gd$email'}[0]->address) ? (string) $entry->{'gd$email'}[0]->address : '';
                    $uc->displayName = isset($entry->title->{'$t'}) ? (string) $entry->title->{'$t'} : '';
                    $uc->identifier = ($uc->email != '') ? $uc->email : '';
                    $uc->description = '';
                    if (property_exists($entry, 'link')) {
                        /**
                         * sign links with access_token
                         */
                        if (is_array($entry->link)) {
                            foreach ($entry->link as $l) {
                                if (property_exists($l, 'gd$etag') && $l->type == "image/*") {
                                    $uc->photoURL = $this->addUrlParam($l->href, array('access_token' => $this->api->access_token));
                                } else if ($l->type == "self") {
                                    $uc->profileURL = $this->addUrlParam($l->href, array('access_token' => $this->api->access_token));
                                }
                            }
                        }
                    } else {
                        $uc->profileURL = '';
                    }
                    if (property_exists($response, 'website')) {
                        if (is_array($response->website)) {
                            foreach ($response->website as $w) {
                                if ($w->primary == true)
                                    $uc->webSiteURL = $w->value;
                            }
                        } else {
                            $uc->webSiteURL = $response->website->value;
                        }
                    } else {
                        $uc->webSiteURL = '';
                    }
                    
                    $contacts[] = $uc;
                }
            }
        }
        
        return $contacts;
    }
    
    /**
     * Add query parameters to the $url
     *
     * @param string $url    URL
     * @param array  $params Parameters to add
     * @return string
     */
    function addUrlParam($url, array $params){      
        $query = parse_url($url, PHP_URL_QUERY);

        // Returns the URL string with new parameters
        if ($query) {
            $url .= '&' . http_build_query($params);
        } else {
            $url .= '?' . http_build_query($params);
        }
        return $url;
    }

}

After changing to this code, my google api is working fine.

7
  • Can you please help me to know , exactly what changes you did Sep 7, 2020 at 13:19
  • this is the only file Hybrid/Providers/Google.php I have changed
    – Mohit Rane
    Sep 8, 2020 at 11:41
  • mageplaza which version u are using? Sep 10, 2020 at 4:48
  • I had used the MagePal module version 1.5.1
    – Mohit Rane
    Sep 10, 2020 at 13:18
  • @MohitRane you didn't change the whole file....you have to mention the exact code which you have changed. Sep 21, 2020 at 7:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.