I need to get my access_token and refresh_token for OAuth 2.0 to Access Google APIs, the php script below should return a json with access_token, refresh_token like this:
{
"access_token" : "####",
"token_type" : "Bearer",
"expires_in" : 3600,
"refresh_token" : "####"
}
but, the php script return me only this error message:
{
"error" : "invalid_request",
"error_description" : "Client must specify either client_id or client_assertion, not both"
}
I tried to remove client_secret/client_id and use only client_id/client_secret, but still get the same error.
PHP script
$client_id = '###.apps.googleusercontent.com';
$redirect_uri = 'http://localhost/phpConnectToDB/csv/refreshFusionTable.php';
$client_secret = '###';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://accounts.google.com/o/oauth2/token");
$code = $_REQUEST['code'];
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_POSTFIELDS, array(
'code' => $code,
'client_id' => $clientID,
'client_secret' => $clientSecret,
'redirect_uri' => $redirect_uri,
'grant_type' => 'authorization_code'
));
$data = curl_exec($ch);
var_dump($data);
Although curl in cmd works and returns me access and refresh token without any errors.
curl --data "code=###&client_id=###.apps.googleusercontent.com&client_secret=###&redirect_uri=http://localhost/phpConnectToDB/csv/refreshFusionTable.php&grant_type=authorization_code" https://accounts.google.com/o/oauth2/token
I don't understand why I get the missing scheme error, although the .php script exists and it's located on the given path. Could you help me please ?
EDIT Problem with "Invalid parameter value for redirect_uri: Missing scheme" solved, I just replaced 'redirect_uri' => urlencode($redirect_uri), with this 'redirect_uri' => $redirect_uri, in CURLOPT_POSTFIELDS.
Wow, stupid mistake, I should have a rest.
The variables names don't match.
I defined:
$client_id = '###.apps.googleusercontent.com';
$client_secret = '###';
But here I used an non-existing clientID and clientSecret :
curl_setopt($ch, CURLOPT_POSTFIELDS, array(
'code' => $code,
'client_id' => $clientID,
'client_secret' => $clientSecret,
'redirect_uri' => $redirect_uri,
'grant_type' => 'authorization_code'
));
Fixed and working PHP script
$client_id = '###.apps.googleusercontent.com';
$redirect_uri = 'http://localhost/phpConnectToDB/csv/refreshFusionTable.php';
$client_secret = '###';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://accounts.google.com/o/oauth2/token");
curl_setopt($ch, CURLOPT_POST, TRUE);
$code = $_REQUEST['code'];
// This option is set to TRUE so that the response
// doesnot get printed and is stored directly in
// the variable
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_POSTFIELDS, array(
'code' => $code,
'client_id' => $client_id,
'client_secret' => $client_secret,
'redirect_uri' => $redirect_uri,
'grant_type' => 'authorization_code'
));
$data = curl_exec($ch);
var_dump($data);
But I have to say that google provides a little misleading error message here, because I hadn't defined client_id nor client_secret and the error message was:
{
"error" : "invalid_request",
"error_description" : "Client must specify either client_id or client_assertion, not both"
}
Related
I have been unable to get an OAuth token. I have spent about 4 hours trying. The various iterations and changes the Twitch API has been through is leaving me unsure and confused. The Twitch Developers now have a message posted stating V5 API being decommission on February 28th 2022. I am lost.
This is where I am at right now. The "code" below is from the Getting authorization code here.
<?php
function file_get_contents_curl($url) {
$curlHeader = [
'client_id' => '"CLIENT ID"',
'client_secret' => '"CLIENT SECRET"',
'code' => '"POST TOKEN"',
'grant_type' => '"AUTHENTICATION CODE"',
'redirect_uri' => 'https://rons-home.net'
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_AUTOREFERER, TRUE);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
curl_setopt($ch, CURLOPT_HTTPHEADER, $curlHeader);
$data = curl_exec($ch);
curl_close($ch);
return $data;
}
print_r( file_get_contents_curl( 'https://id.twitch.tv/oauth2/authorize' ) );
Response
{"status":400,"message":"missing response type"}
This is a valid curl call to do the Step 3 of user oAuth
Most notably:
you were trying to pass paramters as a header
And you have extra " littered in your paramerters
And your grant type if very wrong
Substitute the constants as needed.
$ch = curl_init('https://id.twitch.tv/oauth2/token');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, array(
'client_id' => CLIENT_ID,
'client_secret' => CLIENT_SECRET,
'code' => $_GET['code'],
'grant_type' => 'authorization_code',
'redirect_uri' => REDIRECT_URI
));
// fetch the data
$r = curl_exec($ch);
// get the information about the result
$i = curl_getinfo($ch);
// close the request
curl_close($ch);
<?php
$client_id = "XXXXXXXXX1";
$client_secret = "XXXXXXXXXX2";
$redirect_URI = "XXXXXXXXX3";
$auth_code = htmlspecialchars($_GET["code"]);
$post_field_array = array(
'client_id' => $client_id,
'client_secret' => $client_secret,
'grant_type' => 'authorization_code',
'code' => $auth_code,
'redirect_uri' => $redirect_uri,
'scope' => 'basic genomes');
$post_fields = '';
foreach ($post_field_array as $key => $value)
$post_fields .= "$key=" . urlencode($value) . '&';
$post_fields = rtrim($post_fields, '&');
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.23andme.com/token/');
curl_setopt($ch, CURLOPT_POST, count($post_field_array));
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_fields);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
$encoded_json = curl_exec($ch);
$response = json_decode($encoded_json, true);
$access_token = $response['access_token'];
print $access_token;
?>
This script is run from the same URL as $redirect_URI, per the specifications of the 23andMe API (https://api.23andme.com/docs/authentication/). However, no matter what I try, the script simply outputs nothing. What am I doing wrong here?
I do not know why it doesn't work but I would suggest you to do some debugging. Start with
print_r($encoded_json)
(or use var_dump) and see what the output of that might be. Does curl_exec fail?
Try setting the verbose flag to curl and see if that will throw any errors(warnings) that can push you towards the issue
curl_setopt($ch, CURLOPT_VERBOSE, true);
First up, I get these 3 notices,
code doesn't exist unless I pass it on the querystring, redirect_uri has different case in both uses, access_token probably doesn't exist, because an error authenticating occurred
Notice: Undefined index: code in test.php on line 6
Notice: Undefined variable: redirect_uri in test.php on line 13
Notice: Undefined index: access_token in test.php on line 29
<?php
$client_id = "XXXXXXXXX1";
$client_secret = "XXXXXXXXXX2";
$redirect_uri = "XXXXXXXXX3"; // FIXED VARIABLE NAMING HERE
$auth_code = htmlspecialchars($_GET["code"]);
$post_field_array = array(
'client_id' => $client_id,
'client_secret' => $client_secret,
'grant_type' => 'authorization_code',
'code' => $auth_code,
'redirect_uri' => $redirect_uri,
'scope' => 'basic genomes');
$post_fields = '';
foreach ($post_field_array as $key => $value)
$post_fields .= "$key=" . urlencode($value) . '&';
$post_fields = rtrim($post_fields, '&');
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.23andme.com/token/');
curl_setopt($ch, CURLOPT_POST, count($post_field_array));
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_fields);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
$encoded_json = curl_exec($ch);
$response = json_decode($encoded_json, true);
// DUMP RESPONSE IF ERROR OCCURS, ACCESS WON'T EXIST
var_dump($response);
$access_token = $response['access_token'];
print $access_token;
I'm trying to send a post request to the linkedin API using CURL. For some reason I get a response saying that I'm missing one variable.
array:2 [▼
"error" => "missing_parameter"
"error_description" => "A required parameter "client_id" is missing"
]
Here is my code and I can assure you that cliend_id is set.
$code = $request->get("code");
$state = $request->get("state");
$redirect_uri = "http://example.com/linkedin/callback";
$client_id = "1242435657";
$client_secret = "XXXXXXXXXX";
$url = "https://www.linkedin.com/oauth/v2/accessToken";
$params = array(
"grant_type" => 'authorization_code',
"code" => $code,
"redirect_uri" => $redirect_uri,
"client_id" => $client_id,
"client_secret" => $client_key,
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
$output = curl_exec($ch);
$info = curl_getinfo($ch);
curl_close($ch);
// create an array from the data that is sent back from the API
$result = json_decode($output, 1);
Is there anyway that I could debug this post request?
Remove the comma at the end of the last property and try again perhaps?
$params = array(
"grant_type" => 'authorization_code',
"code" => $code,
"redirect_uri" => $redirect_uri,
"client_id" => $client_id,
"client_secret" => $client_key, <=========
);
I want to create a webhook url for pitifuller form by id here is my code i don't know what is my mistake
define('CLIENT_ID', 'client_id');
define('CLIENT_SECRET', 'client_secret');
define('REDIRECT_URL', 'redirect url'); // for testing, use the URL to this PHP file.
define('AUTHORIZE_URL', 'https://www.formstack.com/api/v2/oauth2/authorize');
define('TOKEN_URL', 'https://www.formstack.com/api/v2/oauth2/token');
$ch = curl_init(TOKEN_URL);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(array(
'grant_type' => 'authorization_code',
'client_id' => CLIENT_ID,
'redirect_uri' => REDIRECT_URL,
'client_secret' => CLIENT_SECRET,
'id' => 'id', // here is my id
'url' => 'web_hook_url' // here is my webhook url which i want to create
)));
// oauth2 contains the the access_token.
$oauth2 = json_decode(curl_exec($ch));
You did mistake in your CURL call, currently you are pass post data in GET form and you need to pass Like this(POST form/:id/webhook), and you can do this:
$ch = curl_init('https://www.formstack.com/api/v2/form/your-form-id/webhook');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Authorization: Bearer ' . $oauth2->access_token
));
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(array(
'id' => $_POST['id'],
'url' => 'http://www.getbravo.com/formstack/index.php',
'append_data' => '1'
)));
and you get response like this
$forms = json_decode(curl_exec($ch));
print '<pre>';
print_r($forms);
print '</pre>';
I'm trying to implement Google's OAuth 2.0 authentication for a web server application.
I can obtain the code from Google ok, but when I post this back to try and get an access token, it always give me the error "Required parameter is missing: grant_type. Error 400" even though the grant_type is there.
Also if I specify the content-length to be anything other than 0, it throws other errors.
Here's the code that's doing this curl post:
$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'
));
try
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'
));
or
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'
);
I was trying to use the PHP code in the original question plus answers provided here and kept getting complaints from the Google token server about a missing "grant_type", even though it was definitely being passed in. It turns out the issue was the CURLOPT_HTTPHEADER didn't like/need the 'Content-length: 0'. Hopefully this complete working code will save someone else the same headache...
// 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);
FYI, the response JSON looks something like this:
{
"access_token" : "xxxWhateverGibberish",
"token_type" : "Bearer",
"expires_in" : 3600,
"refresh_token" : "yyyMoreGibberish"
}
After that I could successfully query the Calendar (the API scope my original OAuth request called for) using code like the following:
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);
}
}
After researching into this problem, it seems like the grant_type is not accepted in the array format. (Yes, the query string method works but it's messy to build.)
Adding http_build_query() to the array works if you are keen on keeping the POST fields in an array.
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'
)));
Please read the documentation for CURLOPT_POSTFIELDS carefully:
... as an array with the field name as key and field data as value
You do just something but not that. Try:
curl_setopt($ch, CURLOPT_POSTFIELDS, array(
'code' => $code,
'client_id' => $clientID,
...
You don't need to urlencode in this case.
I didn't want to believe it, but strangely enough, simply switching from CURLOPT_POSTFIELDS from an array to a '&' concatenated string (with the same data!) let my OAuth server finally recognize the grant_type.
The core issue with the original question and some of the answers is the different values accepted in the curl_setopt call when using the key CURLOPT_POSTFIELDS.
When the input is an array the resulting Content-Type will be multipart/form-data which is not compliant with the OAuth 2.0 spec and the server will ignore it. When the input is a query-encoded string (e.g built using http_build_query) the Content-Type: will be application/x-www-form-urlencoded, which is what the spec requires.
See the "Notes" section at: http://php.net/manual/en/function.curl-setopt.php