I am having this weird issue here in which the instant I get a token via Dropbox and try to test it, an exception is thrown with this message:
HTTP status 401 {"error": "The given OAuth 2 access token doesn't
exist or has expired."}
Why would a Dropbox token expire as soon as I generate it?
Let me show you the flow of my app:
User sees this screen:
Which has the following relevant PHP code:
require "../../includes/dropbox-sdk/Dropbox/autoload.php";
require "../../includes/config.php";
session_start();
session_regenerate_id();
$appInfo = Dropbox\AppInfo::loadFromJsonFile("../../includes/dropbox-sdk/Dropbox/app-info.json");
$webAuth = new Dropbox\WebAuthNoRedirect($appInfo, "Mignori-Box/1.0");
$authorizeUrl = $webAuth->start();
So okay, we generate a Dropbox authorization URL with the official SDK, which seems to be working fine, the user sees this screen:
They click allow, Dropbox gives them an Authorization token, then they paste it into my site, and submit it. This is the code that processes the form:
try
{
$accessToken = $_POST['authorization_code'];
$dbxClient = new Dropbox\Client($accessToken, "Mignori-Box/1.0");
$accountInfo = $dbxClient->getAccountInfo();
}catch(Exception $e)
{
echo "<div class=\"alert alert-danger\">";
echo "<strong>An error has occurred.</strong><br>" . $e -> getMessage();
echo "</div>";
}
But no matter how recent the token is, when the user submits the token the catch is called and the warning displayed. Even if the token was generated literally seconds ago, this happens.
Can someone please enlighten me as to what's wrong?
I was forgetting the step to convert the authorization code into an access token.
list($accessToken, $dropboxUserId) = $webAuth->finish($authCode);
In other words, I was indeed using the wrong token. Haha. Last snippet of code should be:
try
{
list($accessToken, $dropboxUserId) = $webAuth->finish($_POST['authorization_code']);
$dbxClient = new Dropbox\Client($accessToken, "Mignori-Box/1.0");
$accountInfo = $dbxClient->getAccountInfo();
}catch(Exception $e)
{
echo "<div class=\"alert alert-danger\">";
echo "<strong>An error has occurred.</strong><br>" . $e -> getMessage();
echo "</div>";
}
Related
Hi everyone i am new in dropbox api (php version).
i am getting authCode using authorizeUrl, its working good for only one time if i reload page error message shows on
'HTTP status 400 {"error_description": "code has expired (within the last hour)", "error": "invalid_grant"}
how to get permanent authCode from dropbox.
$appInfo = dbx\AppInfo::loadFromJsonFile("api-key.json");
$webAuth = new dbx\WebAuthNoRedirect($appInfo, "PHP-Example/1.0");
$authorizeUrl = $webAuth->start();
echo "1. Go to: " . $authorizeUrl . "\n";
echo "2. Click \"Allow\" (you might have to log in first).\n";
echo "3. Copy the authorization code.\n";
$authCode = "****************************************";
list($accessToken, $dropboxUserId) = $webAuth->finish($authCode);
print "Access Token: " . $accessToken . "\n";
$dbxClient = new dbx\Client($accessToken, "PHP-Example/1.0");
$accountInfo = $dbxClient->getAccountInfo();
print_r($accountInfo);
Found the solution in this error
some steps to solve this problem
go to Apps page Dropbox apps
add your site or localhost link to OAuth 2 Redirect URIs
next to generate access token, then copy the access token and use it .
finally remove this lines
list($accessToken, $dropboxUserId) = $webAuth->finish($authCode);
print "Access Token: " . $accessToken . "\n";
and paste directly in your access token into
$accessToken =
"VTEp2cvkQ8************************************";
it's working perfectly
I'm using the code below on my website to try and post a message on a Facebook page that I manage. I'm using the Facebook PHP SDK v5. Whenever I run the code I get directed to Facebook with an error window that says,
"URL Blocked: This redirect failed because the redirect URI is not whitelisted in the app’s Client OAuth Settings. Make sure Client and Web OAuth Login are on and add all your app domains as Valid OAuth Redirect URIs."
However, if I go to the Graph API Explorer and request a User Access Token, then hard code the access token into the script it works just fine. I added Facebook Login to the products tab on my app setting, since that's the only place you can add in the "Valid OAuth redirect URIs". I'm pretty sure the problem is coming from the "Valid OAuth redirect URIs" field in the setting area. I'm not sure what to put in that field or if that is even the problem at all. Currently, I've tried putting the following in the "Valid OAuth redirect URIs" field with no luck;
just my domain i.e. www.my-domain.com
the full path the the calling script i.e. www.my-domain.com/calling-script.php
the full path to a blank page on my server i.e. www.my-domain.com/blank.html
None are working. This is my first go at trying to use the Facebook PHP SDK so I'm sure I'm doing it all wrong... Wondering if anyone is able to give me some guidance on this?
UPDATE:
See answer posted below with fix. My original post was not very clear regarding my intentions. My goal was to successfully post a message to a Facebook Page as the Page, not as an individual user. Hope this helps someone down the road.
Here are my app settings:
Here is the PHP script I am using:
session_start();
$path = "path-to-Facebook-autoloader-on-my-server";
include_once $path;
$fb = new Facebook\Facebook([
'app_id' => 'app-id-from-app-settings',
'app_secret' => 'app-secret-number-from-app-settings',
'default_graph_version' => 'v2.7',
]);
/////////////////////////////////////////////////////////////////////////
// If I uncomment the below line the script works fine, but the token expires often
// and I do not want to have to keep updating it
// $_SESSION['facebook_access_token'] = "access-token-obtained-from-Graph-API-Explorer";
/////////////////////////////////////////////////////////////////////////
$helper = $fb->getCanvasHelper();
$permissions = ['email', 'publish_actions']; // optional
try {
if(isset($_SESSION['facebook_access_token'])){
$accessToken = $_SESSION['facebook_access_token'];
}else{
$accessToken = $helper->getAccessToken();
}
}catch(Facebook\Exceptions\FacebookResponseException $e){
// When Graph returns an error
echo 'Graph returned an error: ' . $e->getMessage();
exit;
}catch(Facebook\Exceptions\FacebookSDKException $e){
// When validation fails or other local issues
echo 'Facebook SDK returned an error: ' . $e->getMessage();
exit;
}
if(isset($accessToken)){
if(isset($_SESSION['facebook_access_token'])){
$fb->setDefaultAccessToken($_SESSION['facebook_access_token']);
}else{
$_SESSION['facebook_access_token'] = (string)$accessToken;
// OAuth 2.0 client handler
$oAuth2Client = $fb->getOAuth2Client();
// Exchanges a short-lived access token for a long-lived one
$longLivedAccessToken = $oAuth2Client->getLongLivedAccessToken($_SESSION['facebook_access_token']);
$_SESSION['facebook_access_token'] = (string)$longLivedAccessToken;
$fb->setDefaultAccessToken($_SESSION['facebook_access_token']);
}
// validating the access token
try{
$request = $fb->get('/me');
}catch(Facebook\Exceptions\FacebookResponseException $e){
// When Graph returns an error
if($e->getCode() == 190){
unset($_SESSION['facebook_access_token']);
$helper = $fb->getRedirectLoginHelper();
$loginUrl = $helper->getLoginUrl('https://apps.facebook.com/austintestingapp/', $permissions);
echo "<script>window.top.location.href='".$loginUrl."'</script>";
exit;
}
}catch(Facebook\Exceptions\FacebookSDKException $e){
// When validation fails or other local issues
echo 'Facebook SDK returned an error: ' . $e->getMessage();
exit;
}
try{
// message must come from the user-end
$data = ['message' => 'test message...'];
$request = $fb->post('/me/feed', $data);
$response = $request->getGraphNode();
}catch(Facebook\Exceptions\FacebookResponseException $e){
// When Graph returns an error
echo 'Graph returned an error: ' . $e->getMessage();
exit;
}catch(Facebook\Exceptions\FacebookSDKException $e){
// When validation fails or other local issues
echo 'Facebook SDK returned an error: ' . $e->getMessage();
exit;
}
echo $response['id'];
}else{
$helper = $fb->getRedirectLoginHelper();
$loginUrl = $helper->getLoginUrl('https://apps.facebook.com/austintestingapp/', $permissions);
echo "<script>window.top.location.href='".$loginUrl."'</script>";
}
i checked your script. all looks fine except one thing. can u try after changing
$helper = $fb->getCanvasHelper();
to
$helper = $fb->getRedirectLoginHelper();
and see what error it throws if any?
also u can refer to the shared gist. do let us know your error.
https://gist.github.com/gunnrryy/c2c828fc2a77124cc1bed57af5e216df
So I ended up figuring it out. I played around with the script I originally posted and finally got it to work...sort of. No matter how I ran the script messages were always being sent to the page I manage as a notification. They would not show up on the wall. The end goal I was looking for was to post on to a page that I manage as the page, not as myself. Just in case anyone else comes across this the code below works perfect. Also, it does not require you to submit privileges for approval with Facebook.
The answer to my original question in regards to the "Valid OAuth redirect URIs" field. I ended up putting the path to the calling script in that field and it worked fine.
session_start();
$path = "server-path-to-Facebook-autoloader.php";
$permissions = ['manage_pages', 'publish_pages'];
$callback = "full-path-to-the-calling-script(this-script).php";
include_once $path;
$fb = new Facebook\Facebook([
'app_id' => 'app-id-number-here',
'app_secret' => 'app-secret-here',
'default_graph_version' => 'v2.7',
]);
$helper = $fb->getRedirectLoginHelper();
try {
if (isset($_SESSION['facebook_access_token'])) {
$accessToken = $_SESSION['facebook_access_token'];
} else {
$accessToken = $helper->getAccessToken();
}
} catch(Facebook\Exceptions\FacebookResponseException $e) {
// When Graph returns an error
$res['myresponse'] = 'Error: Graph returned a session error: ' . $e->getMessage();
echo $res['myresponse'];
exit;
} catch(Facebook\Exceptions\FacebookSDKException $e) {
// When validation fails or other local issues
$res['myresponse'] = 'Error: Facebook SDK returned a session error: ' . $e->getMessage();
echo $res['myresponse'];
exit;
}
if (isset($accessToken)) {
if (isset($_SESSION['facebook_access_token'])) {
$fb->setDefaultAccessToken($_SESSION['facebook_access_token']);
} else {
// getting short-lived access token
$_SESSION['facebook_access_token'] = (string) $accessToken;
// OAuth 2.0 client handler
$oAuth2Client = $fb->getOAuth2Client();
// Exchanges a short-lived access token for a long-lived one
$longLivedAccessToken = $oAuth2Client->getLongLivedAccessToken($_SESSION['facebook_access_token']);
$_SESSION['facebook_access_token'] = (string) $longLivedAccessToken;
// setting default access token to be used in script
$fb->setDefaultAccessToken($_SESSION['facebook_access_token']);
}
// getting basic info about user
try {
$profile_request = $fb->get('/me');
$profile = $profile_request->getGraphNode();
} catch(Facebook\Exceptions\FacebookResponseException $e) {
// When Graph returns an error
$res['myresponse'] = 'Error: Graph returned a profile request error: ' . $e->getMessage();
echo $res['myresponse'];
session_destroy();
// redirecting user back to app login page
header("Location: ./");
exit;
} catch(Facebook\Exceptions\FacebookSDKException $e) {
// When validation fails or other local issues
$res['myresponse'] = 'Error: Facebook SDK returned a profile request error: ' . $e->getMessage();
echo $res['myresponse'];
exit;
}
// post on behalf of page
$pages = $fb->get('/me/accounts');
$pages = $pages->getGraphEdge()->asArray();
foreach ($pages as $key) {
if ($key['name'] == 'name-of-page-to-post-to') {
$post = $fb->post('/' . $key['id'] . '/feed', array('message' => 'this is an automated test message from Affordable HomeCare...'), $key['access_token']);
$post = $post->getGraphNode()->asArray();
if($post['id'] <> ''){
$res['myresponse'] = "Successfully Posted to Facebook";
}else{
$res['myresponse'] = "Error: Unable to verify post ID";
}
echo $res['myresponse'];
}
}
} else {
$loginUrl = $helper->getLoginUrl($callback, $permissions);
echo "<script>window.top.location.href='".$loginUrl."'</script>";
}
This is rather a basic question. I'm just getting started with using API calls. I'm trying to use the Dropbox API.
My app has the following code:
<?php
require_once "dropbox-sdk/Dropbox/autoload.php";
use \Dropbox as dbx;
$appInfo = dbx\AppInfo::loadFromJsonFile("app-info.json");
$webAuth = new dbx\WebAuthNoRedirect($appInfo, "CharmsBox/1.0");
$authorizeUrl = $webAuth->start();
print "<p>Authorize the App now</p>";
print '
<p class="ui-widget">Auth Key: <input id="authkey">
<a id="btnAuth" class="btn btn-primary btn-large" href="#" tabindex="2">
<span class="glyphicon glyphicon-flash" aria-hidden="true"></span>Authenticate
</a>
</p>';
?>
In another tab, I enter the username and password to authenticate. Dropbox gives the auth code. I'm now supposed to use this code to generate user id and access token as below:
list($accessToken, $userId) = $webAuth->finish($authCode);
echo "Authorization complete.\n";
echo "- User ID: $userId\n";
echo "- Access Token: $accessToken\n";
However since my php code has already finished execution, I'm unable to run the above code. I tried using the following in another php script, and using GET request:
require_once "dropbox-sdk/Dropbox/autoload.php";
use \Dropbox as dbx;
$appInfo = dbx\AppInfo::loadFromJsonFile("app-info.json");
$webAuth = new dbx\WebAuthNoRedirect($appInfo, "CharmsBox/1.0");
if (isset($_GET['authcode'])) {
list($accessToken, $userId) = $webAuth->finish($authCode);
echo "Authorization complete.\n";
echo "- User ID: $userId\n";
echo "- Access Token: $accessToken\n";
return;
} else {
print "Unauthenticated call of script!";
return;
}
However that gives me the following error code:
Fatal error: Uncaught exception 'InvalidArgumentException' with message ''code' must not be null' in /var/www/virtual/mydomain/split/htdocs/dropbox-sdk/Dropbox/Checker.php
The original example script at Dropbox looks like this:
echo "1. Go to: $authorizeUrl\n";
echo "2. Click \"Allow\" (you might have to log in first).\n";
echo "3. Copy the authorization code.\n";
echo "Enter the authorization code here: ";
$authCode = \trim(\fgets(STDIN));
list($accessToken, $userId) = $webAuth->finish($authCode);
echo "Authorization complete.\n";
echo "- User ID: $userId\n";
echo "- Access Token: $accessToken\n";
How can I continue with authentication with the generated accesscode? Specifically, how can I accept a web based input instead of STDIN and continue authentication?
In a web app, you probably want to use dbx\WebAuth, rather than dbx\WebAuthNoRedirect. Check out the web file browser example in the SDK.
I have a PHP set of scripts using Google's Drive API and PHP examples, but I do not seem to be able to cache authorization requests...
<?php
echo 'This is a new request... setting parameters';
$drive_fileid=$_GET['drive_fileid'];
$drive_userid=$_GET['drive_userid'];
$drive_permission=$_GET['drive_permission'];
$_SESSION['drive_fileid']=$drive_fileid;
$_SESSION['drive_userid']=$drive_userid;
$_SESSION['drive_permission']=$drive_permission;
if($_SESSION['drive_fileid']==''){
echo 'Invalid drive file id. Aborting...';
exit;
} else $drive_fileid=$_SESSION['drive_fileid'];
if($_SESSION['drive_userid']==''){
echo 'Invalid drive user id. Aborting...';
exit;
} else $drive_userid=$_SESSION['drive_userid'];
if($_SESSION['drive_permission']==''){
echo 'Invalid drive permission. Aborting...';
exit;
} else $drive_permission=$_SESSION['drive_permission'];
// Now, if we have been through all this before, lets grab stored tokens...
// These never seem to work.
$getFormSQL="SELECT * from `users` where email='".$email."'";
$getFormData=mysql_query($getFormSQL) or die("Died trying to get auth token from the database with this user");
$formRow = mysql_fetch_array($getFormData);
$oauthToken=$formRow['driveoauth'];
$oauthAccessToken=$formRow['driveoauthaccess'];
require_once 'src/Google_Client.php';
require_once 'src/contrib/Google_DriveService.php';
$client = new Google_Client();
$client->setClientId('myappid.apps.googleusercontent.com');
$client->setClientSecret('myclientsecret');
$client->setRedirectUri('https://www.mywebsite.net/driveapi/oauth2callback');
$client->setScopes(array('https://www.googleapis.com/auth/drive'));
$service = new Google_DriveService($client);
$authUrl = $client->createAuthUrl();
// Since we have no token, we redirect the user to the Google Auth page...
if($oauthToken=='')header( 'Location: '.$authUrl ) ;
$authCode = trim($oauthToken);
// Try authenticate access token
try {
$client->setAccessToken($oauthAccessToken);
$authed=1;
} catch (Exception $e) {
echo '<P>Couldnt authenticate access token';
$authed=0;
}
// If that didn't work, lets generate a new one
if($authed==0){
try {
$accessToken = $client->authenticate($authCode);
$client->setAccessToken($accessToken);
} catch (Exception $e) {
header( 'Location: '.$authUrl ) ;
}
echo 'Got an access token: '.$accessToken;
// Save access token
$accessData=json_decode($accessToken,true);
echo '<P>Extracted and saved: '.$accessData['access_token'].'<P>';
$updateQuery ="UPDATE `users` ";
$updateQuery.=" set ";
$updateQuery.="driveoauthaccess='".$accessData['access_token']."'";
$updateQuery.=" where email='".$email."'";
mysql_query($updateQuery) or die("Unable to update database! ".mysql_error());
}
echo '<P><B>Existing permissions on the file/folder:</B><BR>';
$existingpermissions= $service->permissions->listPermissions($drive_fileid);
$existingpermissionarray=$existingpermissions['items'];
?>
Why am I not able to reuse the tokens I generate?
I followed again THIS TUTORIAL to upload a file on Google Drive with php, directly from my REMOTE SERVER: so I have created new API Project from Google API Console, enabled Drive API service, requested OAuth Client ID and Client Secret, wrote them in a script, then upload it together with Google APIs Client Library for PHP folder to this http://www.MYSERVER.com/script1.php, to retrieve Auth code:
<?php
require_once 'google-api-php-client/src/Google_Client.php';
require_once 'google-api-php-client/src/contrib/Google_DriveService.php';
$drive = new Google_Client();
$drive->setClientId('XXX'); // HERE I WRITE MY Client ID
$drive->setClientSecret('XXX'); // HERE I WRITE MY Client Secret
$drive->setRedirectUri('urn:ietf:wg:oauth:2.0:oob');
$drive->setScopes(array('https://www.googleapis.com/auth/drive'));
$gdrive = new Google_DriveService($drive);
$url = $drive->createAuthUrl();
$authorizationCode = trim(fgets(STDIN));
$token = $drive->authenticate($authorizationCode);
?>
When I visit http://www.MYSERVER.com/script1.php I allow authorization and get the Auth code that I can write in a second script. Then I upload it to http://www.MYSERVER.com/script2.php, who looks like:
<?php
require_once 'google-api-php-client/src/Google_Client.php';
require_once 'google-api-php-client/src/contrib/Google_DriveService.php';
$drive = new Google_Client();
$drive->setClientId('X'); // HERE I WRITE MY Client ID
$drive->setClientSecret('X'); // HERE I WRITE MY Client Secret
$drive->setRedirectUri('urn:ietf:wg:oauth:2.0:oob');
$drive->setScopes(array('https://www.googleapis.com/auth/drive'));
$gdrive = new Google_DriveService($drive);
$_GET['code']= 'X/XXX'; // HERE I WRITE AUTH CODE RETRIEVED AFTER RUNNING REMOTE script.php
file_put_contents('token.json', $drive->authenticate());
$drive->setAccessToken(file_get_contents('token.json'));
$doc = new Google_DriveFile();
$doc->setTitle('Test Drive');
$doc->setDescription('Document');
$doc->setMimeType('text/plain');
$content = file_get_contents('drive.txt');
$output = $gdrive->files->insert($doc, array(
'data' => $content,
'mimeType' => 'text/plain',
));
print_r($output);
?>
Well, now the file drive.txt is uploaded on my Google Drive and structure of token.json file is a sort of:
{"access_token":"XXX","token_type":"Bearer","expires_in":3600,"refresh_token":"YYY","created":1365505148}
Now, as you can imagine I can call script2.php and upload file until a certain time. Finally, the point is: I don't want the token to expire, I don't want to allow authorization each time it expire (recalling script1.php): I need to call the script2.php periodically during the day, to upload my file automatically, without user interaction. So, what's the best way to automatically refresh the token forever in this context? Do I need another script? Can I add some code to script2.php? or modify the token.json file? And where can I read the time remaining before the token expire? Thanks!
You don't have to periodically ask for an access token. If you have a refresh_token, PHP client will automatically acquire a new access token for you.
In order to retrieve an refresh_token, you need to set access_type to "offline" and ask for offline access permissions:
$drive->setAccessType('offline');
Once you get a code,
$_GET['code']= 'X/XXX';
$drive->authenticate();
// persist refresh token encrypted
$refreshToken = $drive->getAccessToken()["refreshToken"];
For future requests, make sure that refreshed token is always set:
$tokens = $drive->getAccessToken();
$tokens["refreshToken"] = $refreshToken;
$drive->setAccessToken(tokens);
If you want a force access token refresh, you can do it by calling refreshToken:
$drive->refreshToken($refreshToken);
Beware, refresh_token will be returned only on the first $drive->authenticate(), you need to permanently store it. In order to get a new refresh_token, you need to revoke your existing token and start auth process again.
Offline access is explained in detail on Google's OAuth 2.0 documentation.
After messing a lot I got this to work. I am using one file/script to get the offline token and then a class to do stuff with the api:
require_once 'src/Google/autoload.php'; // load library
session_start();
$client = new Google_Client();
// Get your credentials from the console
$client->setApplicationName("Get Token");
$client->setClientId('...');
$client->setClientSecret('...');
$client->setRedirectUri('...'); // self redirect
$client->setScopes(array('https://www.googleapis.com/auth/drive.file'));
$client->setAccessType("offline");
$client->setApprovalPrompt('force');
if (isset($_GET['code'])) {
$client->authenticate($_GET['code']);
$_SESSION['token'] = $client->getAccessToken();
$client->getAccessToken(["refreshToken"]);
$redirect = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];
header('Location: ' . filter_var($redirect, FILTER_SANITIZE_URL));
return;
}
if (isset($_SESSION['token'])) {
$client->setAccessToken($_SESSION['token']);
}
if (isset($_REQUEST['logout'])) {
unset($_SESSION['token']);
$client->revokeToken();
}
?>
<!doctype html>
<html>
<head><meta charset="utf-8"></head>
<body>
<header><h1>Get Token</h1></header>
<?php
if ($client->getAccessToken()) {
$_SESSION['token'] = $client->getAccessToken();
$token = json_decode($_SESSION['token']);
echo "Access Token = " . $token->access_token . '<br/>';
echo "Refresh Token = " . $token->refresh_token . '<br/>';
echo "Token type = " . $token->token_type . '<br/>';
echo "Expires in = " . $token->expires_in . '<br/>';
echo "Created = " . $token->created . '<br/>';
echo "<a class='logout' href='?logout'>Logout</a>";
file_put_contents("token.txt",$token->refresh_token); // saving access token to file for future use
} else {
$authUrl = $client->createAuthUrl();
print "<a class='login' href='$authUrl'>Connect Me!</a>";
}
?>
</body>
</html>
You can load refresh token from file and use it as necessary for offline access:
class gdrive{
function __construct(){
require_once 'src/Google/autoload.php';
$this->client = new Google_Client();
}
function initialize(){
echo "initializing class\n";
$client = $this->client;
// credentials from google console
$client->setClientId('...');
$client->setClientSecret('...');
$client->setRedirectUri('...');
$refreshToken = file_get_contents(__DIR__ . "/token.txt"); // load previously saved token
$client->refreshToken($refreshToken);
$tokens = $client->getAccessToken();
$client->setAccessToken($tokens);
$this->doSomething(); // go do something with the api
}
}
More here: https://github.com/yannisg/Google-Drive-Uploader-PHP