facebook long term token "(#200) User must have accepted TOS" - facebook-graph-api

From what I've seen no one as given a good answer to this question about using a long term token to publish contents in a Facebook page.
So, I've checked:
My user as permissions to post to that page
My APP as requested enough permissions to publish to the page
I've used the page temporary token to request the long term token to publish to the page
I've got the page temporary token with this GET:
var obj;
FB.api("/me/accounts",
function (response) {
if (response && !response.error) {
obj = response;
}
}
);
obj.data[1] -> Has the temporary page token that allows me to get the Long term token
I've got the long term token with this GET:
https://graph.facebook.com/oauth/access_token?
grant_type=fb_exchange_token&
client_id={app-id}& client_secret={app-secret}& fb_exchange_token={short-lived-token}
and when I try to post to the page I have a OAUTHException
"(#200) User must have accepted TOS"
I am using Facebook SDK for Javascript.
Can someone tell me what the "User must have accepted TOS" mean?
Thanks in advance

Related

How does one keep a user logged in with Django Rest Framework?

I'm new to Django coming from the Firebase world, where authentication and keeping a user logged in is super easy.
In learning Django (Rest Framework) I came to find out that you can log in a user, get a token and save the token in Cookies to reuse is next time that same user goes into the website. Is this the best way to keep a user logged in?
So far, I can log a user in, get their token and some additional info, but I'm not sure how to prevent this from happening over and over again. I'd like to know how to keep the user logged in.
Also, whenever the user gets back on the browser, do I place a POST request to get their own information (if needed to display on the screen)? Always?
I'm very confused as to how authentication/logging in works.
An usual way to handle this problem is to use Jwt auth.
You will issue a short lived token alongside a long lived refresh token to your consumer.
https://github.com/jpadilla/django-rest-framework-jwt
On your frontend side you can implement an automatic refresh mechanism when the token expire.
Example with React: https://medium.com/#monkov/react-using-axios-interceptor-for-token-refreshing-1477a4d5fc26
On browser side, it's depend. For example with single page app, you can fetch info only one and store them in a store.
For multi page app, you could still use cookie or local storage to persist data.
Each Request is anonymous/new, even after you login.
Why I keep loggedin?
Once you logged in, server usually reuturn a token and save it in your local browser. Next time you send request, you can add the token in your request. Then server will know it is still the same user.
What is token?
There a many kinds of token: session token, jwt, basic token...
Token is a string of your identity, and jwt(JSON Web Tokens) is one of the most popular authentication(CORS) solution. This is how original jwt looks like:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
And this is how actual jwt data looks like:
# HEADER:ALGORITHM
{
"alg": "HS256",
"typ": "JWT"
}
# PAYLOAD:DATA
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}
# VERIFY SIGNATURE
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
your-256-bit-secret
)
Where do I keep token
Token is storage in your local cookies. For each request, you can get token from local cookies and add to request head. For example, in React:
import Cookies from "universal-cookie"
localCookies = new Cookies();
...
..
fetch(`/api/logs/:id`, {
headers: {
'Content-Type': 'application/json',
'Authorization': 'JWT ' + localCookies.get('token'),
}
})
...
..

Is it even possible to post to a facebook page as a admin [duplicate]

I know how to make a post to a Facebook page via the API using PHP SDK, that is done like this:
$facebook->api('/xxxxxxxxxxx/feed', 'post', array('message'=> 'Hello world!', 'cb' => ''));
Where xxxxxxxxxxx is page id ;)
But doing that, I post to that page as me, Jamie, and not as the Page itself (admin).
So how do I post as Admin/Page instead of myself?
Thanks you for your time!
ANSWER (for lazy people):
First of all you need to make sure you have access to manage pages for user, ex:
<fb:login-button autologoutlink="true" perms="manage_pages"></fb:login-button>
Now you also gets a special token for every page user have access to once you get them.
PHP SDK Example:
//Get pages user id admin for
$fb_accounts = $facebook->api('/me/accounts');
//$fb_accounts is now an array
//holding all data on the pages user is admin for,
//we are interested in access_token
//We save the token for one of the pages into a variable
$access_token = $fb_accounts['data'][0]['access_token'];
//We can now update a Page as Admin
$facebook->api('/PAGE_ID/feed', 'post', array('message'=> 'Hello!', 'access_token' => $access_token, 'cb' => ''));
Check out this note regarding your question: http://developers.facebook.com/docs/api > Authorization > Page impersonation.
Long story short, you need the manage_pages extended permission.
And btw, have you checked this first ?

Why is the accesstoken not set by PFFacebookUtils logInInBackgroundWithReadPermissions method?

For reference: I am using the latest Facebook IOS SDK v4 and the latest Parse v1.7.4 and ParseFacebookUtilsV4 SDK.
So I am using PFFacebookUtils loginInBackgroundWithReadPermissions:block: method to have the user login with Facebook credentials and create a PFUser with those credentials.
And then proceeded to make a facebook graph request with FBSDKGraphRequest which from what i read, assumes a valid token has been set (there is no passing of a token parameter to it).
But the facebook graph request failed, and in tracing the issue, I noticed that the "access token" is never set by the loginInBackgroudnWithReadPermissions method. What this method only does is to create a PFUser and a Session instance in Parse, and store there the session token string, but it does not set the currentAccessToken . When I do a [[FBSDKAccessToken currentAccessToken] tokenString] call within the block, I get (null). But if I read the "token string" from the PFSession class I get the "token string" store in the Session class instance in Parse.
See the code below:
- (IBAction)fbLoginAction:(id)sender {
// Set permissions required from the facebook user account
NSArray *permissionsArray = #[ #"email", #"user_friends"];
// Login PFUser using Facebook
[PFFacebookUtils logInInBackgroundWithReadPermissions:permissionsArray block:^(PFUser *user, NSError *error) {
if (!user) {
NSLog(#"Uh oh. The user cancelled the Facebook login.");
} else if (user.isNew) {
NSLog(#"User signed up and logged in through Facebook!");
// Check if the current token has been set
NSLog(#"self.myCurrentToken string = %#", [[FBSDKAccessToken currentAccessToken] tokenString]); // returns (null)
// Get the token string from the PFSession
[PFSession getCurrentSessionInBackgroundWithBlock:^(PFSession *session, NSError *error) {
NSString *tokenString = session.sessionToken;
NSLog(#"Session token = %#", tokenString);
}];
}
And here is the debug console output
So I am not sure what is happening.
IF the PFSession token is set to something shouldn't the FBSDKAccessToken currentAccessToken not be returning this same PFsession token?
And if I were to set the accessToken manually, how can I convert the tokenstring that is stored in Parse to an FBSDKAccessToken instance? There seems to be no method to do this?
thanks
This is happening because you need to add the following code to the bottom of AppDelegate didFinishLaunchingWithOptions :
return [[FBSDKApplicationDelegate sharedInstance] application:application
didFinishLaunchingWithOptions:launchOptions];
By adding the code, your currentAccessToken will no longer be nil and you can make requests to FB right away.
FYI, I was able to discover the acccessToken was nil because I got the following error every time I tried to use FBSDKGraphRequest. So if anyone else gets the error below, make sure your accessToken is not nil even after you log in!
{"error":{"message":"An active access token must be used to query information about the current user.","type":"OAuthException","code":2500}}
#jhk:
Yes. I got an explanation from Facebook support. Login in through Parse is a two step process. First step, is the authorization step, where the user authenticates with Facebook. It switches to Facebook app, and the app receives Facebook access token when it completes successfully. And the second step is , the app authenticates with Parse (i.e your app) using the Facebook token. If it matches existing user/session, you are logged in successfully. However, I was deleting the PFSession manually from the parse backend, while testing every single time I tried to login, so that invalidated the session stored in the backend, and after the 1st step, when the app gets authorized and gets the accesstoken, the system realizes that the local session doesn't match the parsed stored session and invalidated the accesstoken, it sets it to nil. That is why I am seeing the token being set to nil.

the target user has not authorized this action facebook graph api

I am trying to post on user wall on behalf of the application.
Here's what I am doing.
First I get the user access_token from facebook connect and then I reciever an extended access token by using the following call
https://graph.facebook.com/oauth/access_token?
client_id=APP_ID&
client_secret=APP_SECRET&
grant_type=fb_exchange_token&
fb_exchange_token=EXISTING_ACCESS_TOKEN
Now when I try to post on friends wall with the following code.
var params = {};
params['message'] = 'Check out this new gag I\'ve posted about you surely it will piss you off :p';
params['name'] = 'Gagsterz';
params['description'] = 'If you also want to have fun on gagster join in now.';
params['link'] = 'http://localhost/php/backup/View/Profile.php';
params['picture'] = thumbpath;
params['caption'] = 'Caption';
FB.api('/'+victimid+'/feed?access_token="ACCESS_TOKEN", 'post', params, function(response) {
if (!response || response.error) {
var json = $.parseJSON(response.error);
alert(json.code);
alert(JSON.stringify(response.error));
} else {
alert('Published to stream - you might want to delete it now!');
}
});
It gives the following error.
the target user has not authorized this action facebook graph api
with code 200.
I take the permission publish_stream and I've tested it by reverting the permission and then logging in to give permissions to it again and the login windows asks for post on behalf permission.But I am taking the permission while I am retrieving the access token for the first time. Do I have to take the permission again for extended access token ? if yes then how to do so ?
Check your permissions, Do you have permission to Post on wall. By default you will have only read permission.
Check this http://developers.facebook.com/docs/reference/rest/stream.publish/

Accessing signed Facebook JSON using Play 2.0.1 and RestFB

I'm writing an Play 2.0.1 application that will be deployed within a canvas page on Facebook. I'm using restFB for the Facebook API.
By manually creating an Access Token at https://developers.facebook.com/tools/explorer?method=GET I can get my application to access the Facebook user's name and render it in the Canvas page iFrame on Facebook.
So, my app controller receives the POST and renders a page like this:
public static Result handle_fb_post() {
return redirect(routes.canvas.fb_render_profile_page());
}
public static Result fb_render_profile_page() {
String accessToken = "<access token copied from facebook graph explorer>";
DefaultFacebookClient().getExtendedAccessToken(application_id, application_secret);
FacebookClient facebookClient = new DefaultFacebookClient(accessToken);
User fbUser = facebookClient.fetchObject("me", com.restfb.types.User.class);
return ok(views.html.fbuser.render(fbUser));
}
My routes are set up as:
POST /fbcanvas/ controllers.FBCanvas.handle_fb_post()
GET /fbcanvas/profile controllers.FBCanvas.fb_render_profile_page()
However, how can I get access to the signed JSON that Facebook sends me in the POST? I believe that this also contains the access token from the user (assuming that they have authorised my app) as described here:
https://developers.facebook.com/docs/samples/canvas/ (See section on "signed_request Parameter").
There are a number of examples out there for Java, PHP, Javascript and Python, but I can't find any that describe how to do this in Play 2 or using RestFB. I have tried a number of different approaches, but cannot work out how to access the signed request in Play 2.
Can anyone help and explain how this can be done?
If the token is sent as Json in the POST request, you can grab it via
def handle_post() = Action { implicit request =>
val jsonBody = request.body.asJson
//process it
}