title: Google Sign In for Websites causing "Signature verification failed" with JWT PHP library
body: <p>Google web sign in has driven me positively crazy...</p>
  
  <p>I'm building a simple web application, and I'm trying to integrate Google's sign in feature into the website (<a href="https://developers.google.com/identity/sign-in/web/" rel="noreferrer">https://developers.google.com/identity/sign-in/web/</a>).</p>
  
  <p>The JavaScript seemed to go fairly well, and the next step was to verify the <code>id_token</code> I was receiving with my backend server (again, against Google's recommendation: <a href="https://developers.google.com/identity/sign-in/web/backend-auth" rel="noreferrer">https://developers.google.com/identity/sign-in/web/backend-auth</a>).</p>
  
  <p>It's a PHP-based web application, and I've successfully installed the Google Client API library using composer: <code>composer require google/apiclient</code>, but when posting my <code>id_token</code> value to my PHP backend system I'm consistently receiving the following error:</p>
  
  <pre><code>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-&gt;verifyIdToken('eyJhbGciOiJSUzI...', '10...')
  </code></pre>
  
  <p>I've also used the <code>id_token</code> value on Google's "tokeninfo" endpoint (<a href="https://www.googleapis.com/oauth2/v3/tokeninfo?id_token=ABC123" rel="noreferrer">https://www.googleapis.com/oauth2/v3/tokeninfo?id_token=ABC123</a>), and the <code>id_token</code> validates perfectly, so I'm sure it's not the <code>id_token</code> 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.</p>
  
  <p>Here's my code:</p>
  
  <p>Javascript:</p>
  
  <pre><code>&lt;script src="https://apis.google.com/js/platform.js?onload=googleAppStart" async defer&gt;&lt;/script&gt;
  &lt;script&gt;
      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');
          }
      }
  &lt;/script&gt;
  </code></pre>
  
  <p>...and my PHP catching the POST:</p>
  
  <pre><code>&lt;?php
  
      require_once '/vendor/autoload.php';
  
      $credentials = array("client_id" =&gt; "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-&gt;verifyIdToken($id_token);
      }
  
  ?&gt;
  </code></pre>
  
  <p>Thank you so much for taking the time to read this, and for any assistance! It's greatly appreciated!</p>