CURL OAuth 2.0 API Google возвращает «отсутствует обязательный параметр: grant_type» - PullRequest
4 голосов
/ 20 ноября 2011

Я пытаюсь реализовать аутентификацию Google OAuth 2.0 для приложения веб-сервера.

Я могу получить код в Google, но когда я отправляю его обратно, чтобы попытаться получить токен доступа, он всегдавыдает ошибку «Обязательный параметр отсутствует: grant_type. Error 400», даже если есть grant_type.

Кроме того, если я указываю длину содержимого, отличную от 0, он выдает другие ошибки.

Вот код, который делает этот пост:

$url = 'https://accounts.google.com/o/oauth2/token';
$ch = curl_init($url);

curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);  
curl_setopt($ch, CURLOPT_FAILONERROR, false);  
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST'); 

curl_setopt($ch, CURLOPT_HTTPHEADER, array(
    'Content-Type: application/x-www-form-urlencoded',
    'Content-length: 0'
));

curl_setopt($ch, CURLOPT_POSTFIELDS, array( 
    'code='. urlencode($code),
    'client_id=' . urlencode($clientID),
    'client_secret=' . urlencode($clientSecret),
    'redirect_uri=http%3A%2F%2Flocalhost%2Fexperiments%2FnewGALogin.php',
    'grant_type=authorization_code'
)); 

Ответы [ 6 ]

7 голосов
/ 20 ноября 2011

попробуй

curl_setopt($ch, CURLOPT_POSTFIELDS, array( 
    'code' => $code,
    'client_id' => $clientID,
    'client_secret' => $clientSecret,
    'redirect_uri' => 'http%3A%2F%2Flocalhost%2Fexperiments%2FnewGALogin.php',
    'grant_type' => 'authorization_code'
)); 

или

curl_setopt($ch, CURLOPT_POSTFIELDS,
    'code=' . urlencode($code) . '&' .
    'client_id=' . urlencode($clientID) . '&' .
    'client_secret=' . urlencode($clientSecret) . '&' .
    'redirect_uri=http%3A%2F%2Flocalhost%2Fexperiments%2FnewGALogin.php' . '&' .
    'grant_type=authorization_code'
); 
1 голос
/ 06 января 2016

Я пытался использовать код PHP в исходном вопросе плюс ответы, представленные здесь, и продолжал получать жалобы от сервера токенов Google на отсутствующий «grant_type», хотя он определенно передавался. Оказывается, проблема заключалась в том, чтоCURLOPT_HTTPHEADER не понравилось / не нужно 'Content-length: 0'.Надеюсь, что этот полный рабочий код спасет кого-то еще от такой же головной боли ...

// This is what Google's OAUTH server sends to you
$code = $_GET['code'];

// These come from your client_secret.json file
$clientID = "your client id.apps.googleusercontent.com";
$clientSecret = "your client secret";
$redirectURI = "your redirect URI";
$token_uri = 'https://accounts.google.com/o/oauth2/token';


$ch = curl_init($token_uri);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);  
curl_setopt($ch, CURLOPT_FAILONERROR, false);  
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');

curl_setopt($ch, CURLOPT_HTTPHEADER, array(
    'Content-Type: application/x-www-form-urlencoded'
));

// Build the URLEncoded post data
$postFields = http_build_query(array( 
    'client_secret' => $clientSecret,
    'grant_type' => 'authorization_code',
    'redirect_uri' => $redirectURI,
    'client_id' => $clientID,
    'code' => $code
));
curl_setopt($ch, CURLOPT_POSTFIELDS, $postFields); 

$response = curl_exec($ch);

// Save response, especially the "refresh_token"
$pathToAccessToken = "/your/path/to/access_token.json";
file_put_contents($pathToAccessToken, $response);

К вашему сведению, ответ JSON выглядит примерно так:

{
  "access_token" : "xxxWhateverGibberish", 
  "token_type" : "Bearer", 
  "expires_in" : 3600, 
  "refresh_token" : "yyyMoreGibberish" 
}

После этого я могу успешно запроситьCalendar (область действия API, к которой требовался мой исходный запрос OAuth) с использованием кода, подобного следующему:

function getClient() {
  $client = new Google_Client();
  $client->setApplicationName(APPLICATION_NAME);
  $client->setScopes(SCOPES);
  $client->setAuthConfigFile(CLIENT_SECRET_PATH);
  $client->setAccessType('offline');

  // Load previously authorized credentials from a file.
  $pathToAccessToken = "/your/path/to/access_token.json";
  $accessToken = file_get_contents($pathToAccessToken);
  $client->setAccessToken($accessToken);

  // Refresh the token if it's expired.
  if ($client->isAccessTokenExpired()) {
    $client->refreshToken($client->getRefreshToken());
    file_put_contents($pathToAccessToken, $client->getAccessToken());
  }

  return $client;
}

$client = getClient();
$service = new Google_Service_Calendar($client);

// Print the next 10 events on the user's calendar.
$calendarId = 'primary';
$optParams = array(
      'maxResults' => 10,
      'orderBy' => 'startTime',
      'singleEvents' => TRUE,
      'timeMin' => date('c'),
);
$results = $service->events->listEvents($calendarId, $optParams);

if (count($results->getItems()) == 0) {
    print "No upcoming events found.\n";
} else {
    print "Upcoming events:\n";
    foreach ($results->getItems() as $event) {
        $start = $event->start->dateTime;
        if (empty($start)) {
          $start = $event->start->date;
        }
        printf("%s (%s)\n", $event->getSummary(), $start);
    }
}       
1 голос
/ 10 апреля 2015

После исследования этой проблемы кажется, что grant_type не принимается в формате массива.(Да, метод строки запроса работает, но его сложно построить.)

Добавление http_build_query () в массив работает, если вы заинтересованы в сохранении полей POST в массиве.

curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(array( 
    'code' => $code,
    'client_id' => $clientID,
    'client_secret' => $clientSecret,
    'redirect_uri' => 'http%3A%2F%2Flocalhost%2Fexperiments%2FnewGALogin.php',
    'grant_type' => 'authorization_code'
))); 
0 голосов
/ 10 апреля 2015

Основная проблема исходного вопроса и некоторых ответов - это разные значения, принятые в вызове curl_setopt при использовании ключа CURLOPT_POSTFIELDS.

Когда входные данные являются массивом, результирующее Content-Type будет multipart/form-data, что не соответствует спецификации OAuth 2.0, и сервер его игнорирует. Когда входные данные представляют собой строку в кодировке запроса (например, построенную с использованием http_build_query), Content-Type: будет application/x-www-form-urlencoded, что и требуется для спецификации.

См. Раздел «Примечания» по адресу: http://php.net/manual/en/function.curl-setopt.php

0 голосов
/ 23 января 2015

Я не хотел в это верить, но, как ни странно, просто переключаясь с CURLOPT_POSTFIELDS из массива на объединенную строку '&' (с теми же данными!), Мой сервер OAuth наконец-то распознал тип grant_type.

0 голосов
/ 20 ноября 2011

Пожалуйста, внимательно прочитайте документацию для CURLOPT_POSTFIELDS:

... как массив с именем поля в качестве ключа и данными поля в качестве значения

Вы делаете что-то, но только не это. Попробуйте:

curl_setopt($ch, CURLOPT_POSTFIELDS, array( 
    'code' => $code,
    'client_id' => $clientID,
    ...

В этом случае вам не нужно urlencode.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...