Reading the Facebook documentation on Access Tokens, it's a little unclear how to actually write the PHP code to handle them. Testing reveals a little, but I would like to do this correctly.
So, in my app, I use the Javascript SDK to login, and when that comes back, I make an Ajax call to save the access token. The server that handles that call converts that access token to a long-lived token, and stores it in our DB. So far so good.
But in the future calls to the PHP SDK, I want to handle the access token expiring, or the user invalidating the token. My basic SDK calls are like:
try
{
$request = new Facebook\FacebookRequest( $this->fbApp,
$access_token, . . .);
$response = $this->fb->getClient()->sendRequest($request);
// some processing here
}
catch(Facebook\Exceptions\FacebookResponseException $ex)
{
}
catch(Facebook\Exceptions\FacebookSDKException $ex)
{
}
The documentation suggests that I catch exceptions via capturing "the error messages thrown by the API", and gives this information:
{
"error": {
"message": "Error validating access token: Session has expired at unix time SOME_TIME. The current unix time is SOME_TIME.",
"type": "OAuthException",
"code": 190
}
}
with my only method of determining whether the token expired or the user de-authorized the app being doing a string comparison on the error message, or looking at a subcode (which, of course, are defined somewhere else. blech).
My main question is - will token errors always be thrown as FacebookResponseExceptions? I did a test with de-authorizing the app, and got that exception code of 190, and a message "Error validating access token: The user has not authorized application". Is there a way to get the subcode? Or do I just assume that an error code of 190 always means send them back through the login process?
And what about expired tokens? Tough to test that, will that throw an exception, or will the response from the SDK call be an error?
thanks...
An OAuthException is a pretty sure indicator that either the token is not valid any more, or that you don’t have the permission necessary to perform the desired action – both cases in which you likely want to send the user through the login flow again.
For a list of some possible error codes, and general instructions on how you should generally handle the, see https://developers.facebook.com/docs/graph-api/using-graph-api/v2.5#errors
In case you run into such an OAuthException, you might want to debug the token that you have stored – that will tell you if it is still valid or not: https://developers.facebook.com/docs/facebook-login/access-tokens#debug
And if it is, you might want to do a call for /me/permissions next, to find out what permissions the user has granted your app. You can also check for a specific permission via /me/permissions/permission_name.
Related
I have a problem about the error code 105 (Message: "Authentication failed. Either supplied credentials are invalid or the account is inactive") when performing a "GetUser" request. I've already understand that it's because of an incorrect access token (AuthenticationToken header element) or developer token for the target environment. So it must be about the way I set my credentials (or my credentials). Here is my code:
public function getAuthorization()
{
$result = AuthController::getRefreshToken(); //get The refresh token, update it if necessary
AuthController::WriteOAuthRefreshToken($result); //stock the refresh token
$authentication = (new OAuthWebAuthCodeGrant())
->withEnvironment(AuthController::ApiEnvironment) //production
->withClientSecret(AuthController::ClientSecret)
->withClientId(AuthController::ClientId)
->withOAuthTokens(
(new OAuthTokens())
->withAccessToken(json_decode($result, true)["access_token"])
->withRefreshToken(json_decode($result, true)["refresh_token"])
->withAccessTokenExpiresInSeconds(3600))
->withRedirectUri(AuthController::RedirectUri)
->withState(rand(0,999999999));
$GLOBALS['AuthorizationData'] = (new AuthorizationData())
->withAuthentication($authentication)
->withDeveloperToken(AuthController::DeveloperToken);
AuthController::Authenticate();
}
And here is the function to Authenticate which call the getUser Function ()
static function Authenticate()
{
// Authenticate for Bing Ads services with a Microsoft Account. Perform a $GLOBALS['AuthorizationData']->Authentication->RequestOAuthTokensByRefreshToken($refreshToken);
AuthController::AuthenticateWithOAuth();
$GLOBALS['CustomerManagementProxy'] = new ServiceClient(
ServiceClientType::CustomerManagementVersion12,
$GLOBALS['AuthorizationData'],
AuthController::ApiEnvironment);
$GLOBALS['CustomerManagementProxy']->SetAuthorizationData($GLOBALS['AuthorizationData']);
// Here is the problem
$user = AuthController::GetUser(null, true)->User;
}
The getUser function I currently use is the same as the one in the PHP "Code Syntax" part in the documentation.
I'm using the production environment with my own credentials. I've already checked my developer token and all the corresponding rights (which seems correct). I update my tokens each time I'm trying to do that request.
Is there any problems about the way I set the request?
If the problem is about the tokens, is there a way to check if it's correct?
I precise I've tried also with the getAccount function with the same result.
Any ideas? Thanks for your time.
Here are a few ideas to explore:
Can you login to the Bing Ads web application with these credentials i.e., does this user have access to a Bing Ads account?
Is the OAuthTokens->AccessToken set or empty e.g., try var_dump($authentication).
Try refreshing the token directly in the auth object e.g., see this sample.
Log the SOAP request and response to see if AuthenticationToken was set in the GetUser call e.g., immediately after the GetUser call print the last request/response:
print $GLOBALS['Proxy']->GetService()->__getLastRequest()."\n";
print $GLOBALS['Proxy']->GetService()->__getLastResponse()."\n";
Otherwise to confirm credentials you might want to contact Bing Ads support directly.
I hope this helps!
I requested authorization for a public application to be able to access store data via the Shopify API.
The store successfully authorized my application via an authorization request URL such as
https://some-store.myshopify.com/admin/oauth/authorize?client_id=123abc&scope=read_inventory%2Cread_products&redirect_uri=http%3A%2F%mysite.com%2Fauth.php&state=123456
and the response was passed back to my application. This response (containing the code that can be exchanged for a permanent access token) was mishandled by my application (an error on the page meant that the access token was not stored).
Everything I read regarding requesting these tokens involves authorization by the store - but given the store has already authorized my application, passed back the code and that code has already successfully been exchanged for a token: is there a way my application can request that same token or a fresh one using my API keys given that the application is already authorized?
The only method I currently can find for requesting a token requires starting back at the beginning and fetching a code for exchange etc.
I working in PHP and using Luke Towers' php shopify wrapper
This stage was completed successfully:
function check_authorization_attempt()
{
$data = $_GET;
$api = new Shopify($data['shop'], [
'api_key' => '123',
'secret' => '456',
]);
$storedAttempt = null;
$attempts = json_decode(file_get_contents('authattempts.json'));
foreach ($attempts as $attempt) {
if ($attempt->shop === $data['shop']) {
$storedAttempt = $attempt;
break;
}
}
return $api->authorizeApplication($storedAttempt->nonce, $data);
}
$response = check_authorization_attempt();
and I would have been able to read the access token from :
$access_token = $response->access_token;
But this was the stage at which my application hit an error in accessing a database in which to write said token.
I cannot repeat it without repeating the auth request because the data in $_GET that's passed to this function comes from Shopify's response to the shop owner authorizing the access, and includes amoung other things the code for exchange.
You have to re-ask for authorization. It is no one's fault but yours that your persistence layer code was incorrect. So there is nothing you can do to change that. Ensure your code works. Since the client has no token in your App persistence layer, your App will retry the authorization token exchange. They do not have to delete your App first. So basically, the next time your client tries to use the App, YES they will asked to approve it, but who cares, they will, and you'll get a good auth token to store. You have fixed your code (right), so that will work. You are one step closer to glory.
Shopify does return the Permanent Access Token, but the ACCESS_MODE must be "Offline" for the token to be permanent.
With ACCESS_MODE offline, your app receives the permanent access token
to make requests whenever you want, without the user's permission.
Documentation:
https://shopify.dev/tutorials/authenticate-with-oauth#step-2-ask-for-permission
https://shopify.dev/concepts/about-apis/authentication#api-access-modes
I am trying make a registration with FB option for my PHP based website. My callback url for the website is
http://subdomain.mydomain.com/user/fblogincb/
I have added that in the Valid OAuth redirect URIs in my Apps Facebook Login settings. The login button of my website correctly invoke the callback url, but when I try to use the access token in my call back page using the follwing code:
$helper = $fb->getRedirectLoginHelper();
try {
$accessToken = $helper->getAccessToken();
} catch(Facebook\Exceptions\FacebookResponseException $e) {
// When Graph returns an error
echo 'Graph returned an error: ' . $e->getMessage();
exit;
}
it return the exception:
Graph returned an error: Can't Load URL: The domain of this URL isn't included in the app's domains. To be able to load this URL, add all domains and subdomains of your app to the App Domains field in your app settings.
The redirected URL from FB is:
http://subdomain.mydomain.com/user/fblogincb/?code=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
However, turning off the Strict URLs mode does not have this issue. What am I doing wrong here for the Strict URLs mode. Any help will be appreciated.
Try and pass the exact redirect URL that was used in the login dialog call, as parameter to the getAccessToken method:
$accessToken = $helper->getAccessToken('http://subdomain.mydomain.com/user/fblogincb/');
The exact same redirect_uri parameter value must be passed in both calling the login dialog, and in the subsequent API call that exchanges the code for a token. The SDK has its own "URL detection handler" on board (or you can supply your own, in environments where custom routing logic might require that) for the purpose of determining the current URL - which usually does the job fine, but depending on the exact setup, it can fail sometimes.
I am a bit surprised by the error message, I remember seeing a different one in such cases that explicitly mentioned the redirect_uri mismatch ... but maybe while implementing strict mode something changed internally, dunno.
Do not forget to update Facebook PHP SDK to latest v5.6.2, strips code param from Facebook redirect_uri callback
Facebook SDK for PHP - changelog
5.6.2 (2018-02-15)
Strip 'code' param (#913)
I am building a restful API (PHP) to serve iOS and Android applications and I would like to implement facebook login on both apps.
The flaw is like the following :
Clients ( ios or Android ) login with facebook and send an access_token to the restful api
verify if the access_token is authorized to use the application
If token is valid, get user data from graph.
Merge accounts and generate token for different queries.
For security purpose to avoid getting random tokens thatthey don't belong to my APP, I would like to make a test call to check if a token is authorized and valid or not ?
I know many similar questions might be already answered but none of them really give me the right answer and I don't really have experience with facebook graph.
I found this solution :
https://graph.facebook.com/oauth/access_token?client_id=APP_ID&client_secret=SECRET_APP_ID&grant_type=fb_exchange_token&fb_exchange_token=ACCESS_TOKEN
This works somehow .. it whether give me an error, or an access token (string format not JSON) and I am not sure if this is the best way to test or not.
Note: I am still in early stage of development, if you have any suggestion on my flow please let me know, I might be doing things the wrong way ?
What works for my application (code with explanation below)...
$fb = new Facebook\Facebook([
'app_id' => 'XXXXXXX',
'app_secret' => 'XXXXXXX',
'default_graph_version' => 'v2.5',
]);
// My app pulls users' access tokens & page ID from a database here and stores in $fb_access_token & $fb_page_id variables
$fb_access_token = 'YOU OR YOUR USERS ACCESS TOKEN GOES HERE';
$fb_page_id = 'ID OF FACEBOOK PAGE OR USER';
$fb->setDefaultAccessToken($fb_access_token);
// CHECK IF ACCESS TOKEN SITLL WORKS
try{
$page = $fb->get('/'.$fb_page_id.'?fields=id', $fb_access_token);
} catch(Facebook\Exceptions\FacebookResponseException $e) {
echo 'Graph returned an error: ' . $e->getMessage();
$graphError = 'Yes';
} catch(Facebook\Exceptions\FacebookSDKException $e) {
echo 'Facebook SDK returned an error: ' . $e->getMessage();
$sdkError = 'Yes';
}
// IF ACCESS TOKEN STILL WORKS...CONTINUE WITH SCRIPT. THIS PREVENTS ACCESS TOKEN FAILURE FROM BREAKING SCRIPT.
if(!isset($graphError) && !isset($sdkError)){
// CONTINUE WITH SCRIPT
}
Explanation: you are taking the access token in question, and attempting to make a GET Request to the Facebook API. Only continue with the rest of your script IF there are NO ERRORS.
You could also add an ELSE statement at the end to maybe redirect the user to a page where they can re-authenticate their account/access token, depending on what your app is doing.
My app uses a couple of WHILE Loops to go through my database of users, and depending on certain column/cell values, it POSTS to their Facebook page for them...
Before this solution...when the Loop came across an invalid Access Token, it "broke" and did not execute the script for the rows following the "unauthenticated user" because it was making a failed request.
Hope this helps someone!
“Random” tokens would not work anyway. (Tokens issued by Facebook are encrypted, so the API can tell whether a token is genuine, or just "random". At most you'd need to worry about what a user possible could using a token for a different app, or one they themselves granted more permissions than you asked them for.)
Just request the user details using the access token you got - if it is not valid because someone tried to “fake” it, then the API response will tell you so.
The docs have a chapter about securing API requests, go check that out as well: https://developers.facebook.com/docs/graph-api/securing-requests
I'm trying to use the OAuthProvider library from PHP.net and of course, it's not documented. I've followed Rasmus' tutorial and I've followed djpate.com's tutorial and neither of them to work for me and Rasmus doesn't link to any source, the source he does link to for examples is confusing and of course, doesn't work when ran.
I seem to always get a "signatures do not match" error which I don't understand really, because I've followed the tutorials to a T.
What's the flow supposed to be anyway?
1. Create consumer key/secret. Check.
2. Get the access token? I get errors -- Where does the signature come from?
3. Get the request token? I get error
I'm trying to create an OAuthProvider so that I can create 1 consumer account that can call my API remotely and it seems like this is very poorly documented for a beginner... in PHP land anyway.
If anyone has any working OAuthProvider libraries or can explain this to me in more detail I would greatly appreciate it.
Thanks in advance.
http://oauth.net/core/1.0a/ tells you the basic flow.
A consumer gets a consumer key and secret.
The consumer gets a request token.
The consumer redirects the user to the provider's authentication endpoint.
The user signs the request token (or doesn't).
The consumer swaps a authentication token for their signed request token.
The consumer uses their authentication token to access protected information.
http://oauth.net/core/1.0a/#signing_process describes how a request is signed.
"The signature process encodes the Consumer Secret and Token Secret
into a verifiable value which is included with the request."
If you are using the pecl oauth/oauthprovider code, the signature is automatically generated on both sides for you (undocumented but true). You can check to see what the signature is by putting the following in the oauthexception catch section in the provider:
catch (OAuthException $E)
{
error_log(print_r($this->provider, true));
echo OAuthProvider::reportProblem($E);
$this->oauth_error = true;
}
and the following in your oauth consumer oauthexception catch section:
catch(OAuthException $E)
{
error_log(print_r($oauth, true));
echo $E->getMessage();
}
In this way you can check your error logs to find out what the signatures are and whether they do in fact not match.
I am having similar error. This seems to be caused, in my case, due to a signature mismatch in http vs https url.
I would check if you are getting re-directed between http and https.