Why curls fails to verify google access token whereas browser succeeds?
Asked Answered
P

2

0

with this simple code I manage to get Google's access tokens. See the code:

public function authenticate($code = null) {
  if (!$code) {
     if ($this->log)
        error_log(__CLASS__ . '::authenticate() error: $code is null.');
     return false;
  }
  $client_id = $this->token->get('client_id');
  $client_secret  = $this->token->get('client_secret');
  $redirect_uri = $this->token->get('redirect_uri');
  $url = $this->token->get('token_endpoint');
  $curlPost = 'client_id=' . $client_id . '&client_secret=' . $client_secret . '&redirect_uri=' . $redirect_uri . '&code='. $code . '&grant_type=authorization_code';
  $ch = curl_init();
  curl_setopt($ch, CURLOPT_URL, $url);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  curl_setopt($ch, CURLOPT_POST, 1);
  curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
  curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
  curl_setopt($ch, CURLOPT_POSTFIELDS, $curlPost);
  $buffer = curl_exec($ch);
  $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
  curl_close($ch);
  $data = \json_decode($buffer, true);
  if ($http_code != 200) {
     $log = __CLASS__ . '::authenticate() error: http code not 200. Responded: '.print_r($data, true);
     $return = false;
  } else {
     $this->auth = $data;
     $return = true;
     $log = __CLASS__ . '::authenticate() returns '.$return.' and sets this->auth='.print_r($data, true);
  }
  if ($this->log)
     error_log($log);
  return $return;
}

you can see my project there with a test file.

My question is about the verify() function. When I want to verify Google's access token by typing in the browser sth like https://www.googleapis.com/oauth2/v2/tokeninfo?access_token=.... I get immediately a response from Google but when I try the following function with cURL it fails miserably:

public function verify($access_token = null) {
  if (!$access_token) {
     if ($this->log)
        error_log(__CLASS__ . '::verify() error: $access_token is null.');
     return false;
  }
  $url = $this->token->get('verify_endpoint');
  $curlPost = 'access_token='. $access_token;
  //$curlPost = \http_build_query(array('access_token' => $access_token));
  //$curlPost = array('access_token' => $access_token);
  $ch = curl_init();
  curl_setopt($ch, CURLOPT_URL, $url.'?'.$curlPost);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
  curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
  curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
  //curl_setopt($ch, CURLOPT_VERBOSE, true);
  $buffer = curl_exec($ch);
  $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
  curl_close($ch);
  $data = \json_decode($buffer, true);
  if ($http_code != 200) {
     $log = __CLASS__ . '::verify() error: http code not 200. Responded: '.print_r($data, true);
     $return = false;
  } else {
     $this->verify = $data;
     $log = __CLASS__ . '::verify() sets this->verify='.print_r($data, true);
     $return = true;
  }
  if ($this->log)
     error_log($log);
  return $return;
}

Has this sth to do with cURL? Any answer is welcomed.

Just to clarify: browser request https://www.googleapis.com/oauth2/v2/tokeninfo?access_token=... or with ?id_token=... always succeeds BUT not cURL with the proper tokens in the query part of course.

Perorate answered 22/12, 2017 at 11:27 Comment(5)
I can't help with an answer. However in the first code block this: $curlPost = 'client_id=' . $client_id . '&client_secret=' ...... is bad because you're not encoding URI string. Just let $curlPost an associative array an pass it curl_setopt($ch, CURLOPT_POSTFIELDS, $curlPost); letting curl do the URI encoding jobDarceydarci
$url = $this->token->get('verify_endpoint'); <-- what is that? The only way to verify an access token is to make an api call. Which api call are you making and what is the error you are getting?Anet
@DaImTo Yes, the code uses some helper classes as in github project (github.com/centurianii/googleclient); that's the actual url for verification stored in class GoogleTokenPerorate
@Darceydarci I can authenticate, I can verify with my browser BUT curl still fails on verification with message: Array ( [error_description] => Unsupported content with type: multipart/form-data; boundary=------------------------4771c015d2208399 )Perorate
I suspect the way I use curl in verify() is not a clear GET request; at the end I shouldn't verify at all but still I wonder why curl fails?Perorate
A
0

From your source code here

$this->set('verify_endpoint', 'https://www.googleapis.com/oauth2/v2/tokeninfo');

is calling googles token info end point documentation is used for validating an id token you appear to be passing it an access token. This is not going to work.

TBH i dont understand why you would bother validating an access token. The best way to test if an access token is working is to make the call to the API in question if it doesnt work you will get an error back. Why would you want to make a call to test if it works then use it if it does work your doubling your requests.

Anet answered 22/12, 2017 at 12:36 Comment(6)
Ok, I have the access token, I put in my browser: https://www.googleapis.com/oauth2/v2/tokeninfo?access_token=ya29.Gl... and I can see immediate response! My question is what is going with curl equivalent. You suggest not to do this step?Perorate
I pass id_token from browser: succeeds, from curl: fails! I suspect curl does not make a clear GET request here...Perorate
Probably because what you are giving curl isnt an id token its an access token. Passing an Id_token via a http get will work. Why are you bothering to test this exactly?Anet
$curlPost = 'token_id='. $token_id; <--- try that. Remember an access token is not a token idAnet
I log google's response so i can see Array ( [access_token] => ya29.G...O0 [expires_in] => 3600 [id_token] => eyJhb...Obg [refresh_token] => 1/wLy...9i [token_type] => Bearer )Perorate
then send id tokenAnet
P
0

Problems solved!

After a 2 month searching at last there is an update version of my project wirh cUrl problems solved immediately after started to investigate errors sent by the curl environment.

The browser success ringed a bell that probably there was a DNS issue as these threads repeatedly showcase this:

  1. https://curl.haxx.se/mail/curlphp-2016-10/0000.html
  2. https://forums.rancher.com/t/dns-caching-issues/1566/8 @vincent
  3. https://github.com/GoogleCloudPlatform/google-cloud-php/issues/405
  4. https://github.com/google/google-api-php-client/issues/1184

This discussion from @sanmai about CURLOPT_RESOLVE actually made it working! Also see php manual; The same is proposed here by Luc van Donkersgoed and there by John Hart.

The tricky parts of response headers on GET requests that contain Google's response are discussed here and in other places.

Curl certificates are downloaded from there. A discussion for certificates is there.

A discussion for debugging cUrl here and there.

For a discussion of Expect header and it's implications you can read this and that.

Now cUrl is lightning fast when it connects to google. See my project.

My deepest gratitude to all the users who patiently and kindly support the community. You guys are awesome! many thanks!

Perorate answered 9/1, 2018 at 11:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.