I tried to use the PHP code in the original question, plus the answers provided here, and continued to receive complaints from the Google token server about the lack of “grant_type”, although it was definitely transmitted. It turns out that the problem was CURLOPT_HTTPHEADER did not like / need "Content-length: 0". Hope this full working code saves someone else the same headache ...
// This is what Google 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);
FYI, the JSON response looks something like this:
{ "access_token" : "xxxWhateverGibberish", "token_type" : "Bearer", "expires_in" : 3600, "refresh_token" : "yyyMoreGibberish" }
After that, I was able to successfully complete the calendar request (the API area that my initial OAuth request accessed) using the following code:
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 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 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); } }