Google Sign In for Websites causing "Signature verification failed" with JWT PHP library

Viewed 2495

Google web sign in has driven me positively crazy...

I'm building a simple web application, and I'm trying to integrate Google's sign in feature into the website (https://developers.google.com/identity/sign-in/web/).

The JavaScript seemed to go fairly well, and the next step was to verify the id_token I was receiving with my backend server (again, against Google's recommendation: https://developers.google.com/identity/sign-in/web/backend-auth).

It's a PHP-based web application, and I've successfully installed the Google Client API library using composer: composer require google/apiclient, but when posting my id_token value to my PHP backend system I'm consistently receiving the following error:

Firebase\JWT\SignatureInvalidException
File: .\vendor\firebase\php-jwt\src\JWT.php:112 
Message: Signature verification failed

Stack trace:
#0 .\vendor\google\apiclient\src\Google\AccessToken\Verify.php(103): Firebase\JWT\JWT::decode('eyJhbGciOiJSUzI...', '-----BEGIN PUBL...', Array)
#1 .\vendor\google\apiclient\src\Google\Client.php(712): Google_AccessToken_Verify->verifyIdToken('eyJhbGciOiJSUzI...', '10...')

I've also used the id_token value on Google's "tokeninfo" endpoint (https://www.googleapis.com/oauth2/v3/tokeninfo?id_token=ABC123), and the id_token validates perfectly, so I'm sure it's not the id_token value that's wrong. It's also passing it perfectly via the POST variable to the PHP script, so I'm at a bit of a loss.

Here's my code:

Javascript:

<script src="https://apis.google.com/js/platform.js?onload=googleAppStart" async defer></script>
<script>
    var googleAppStart  = function(){gapi.load('auth2', initGoogleSignIn);};
    var auth            = false;
    function initGoogleSignIn(){
        auth = gapi.auth2.init({
            client_id   : 'client-id-is-here',
            scope       : 'profile'
        });

        auth.attachClickHandler(document.getElementById('my-button'));
        auth.isSignedIn.listen(googleSignInChanged);
        auth.currentUser.listen(googleCurrentUserChanged);

        if (auth.isSignedIn.get() == true)
            auth.signIn();
    }

    function googleSignInChanged(signed_in){}
    function googleCurrentUserChanged(user){
        var auth_response   = user.getAuthResponse();
        var id_token        = auth_response.id_token;
        if (id_token != undefined){
            var url     = '/verify-google-signin';
            var params  = {id_token: id_token};
            jQuery.post(url, params, function(data){}, 'json');
        }
    }
</script>

...and my PHP catching the POST:

<?php

    require_once '/vendor/autoload.php';

    $credentials = array("client_id" => "client-id-is-here");
    $client = new \Google_Client($credentials);

    $data = $_POST;
    if (isset($data['id_token'])) {

        $id_token = trim($data['id_token']);

        // Exception generated here...
        $payload = $client->verifyIdToken($id_token);
    }

?>

Thank you so much for taking the time to read this, and for any assistance! It's greatly appreciated!

6 Answers

This has been fixed in v2.2.1 of google/apiclient so make sure you are running this version or later if anyone else encounters this issue.

Related discussions here and here.

If you are not using Firebase (taken from https://github.com/googleapis/google-api-php-client)

 rm -r vendor/google/apiclient-services

Add this to composer.json

    "scripts": {
        "post-update-cmd": "Google\\Task\\Composer::cleanup"
    },
    "extra": {
        "google/apiclient-services": [
            "Drive"  ,
            "... any other services here ...",
      ]
    }

Finally

composer install

This will resolve the error message with the added benefit of drastically reducing installed packages. As noted, there are at least 200 API services for GAPI

Related