Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Obtaining a Facebook auth token for a command-line (desktop) application

Tags:

I am working for a charity which is promoting sign language, and they want to post a video to their FB page every day. There's a large (and growing) number of videos, so they want to schedule the uploads programmatically. I don't really mind what programming language I end up doing this in, but I've tried the following and not got very far:

  • Perl using WWW::Facebook::API (old REST API)

    my $res = $client->video->upload(
     title => $name,
     description => $description,
     data => scalar(read_file("videos/split/$name.mp4"))
    );
    

    Authentication is OK, and this correctly posts a facebook.video.upload method to https://api-video.facebook.com/restserver.php. Unfortunately, this returns "Method unknown". I presume this is to do with the REST API being deprecated.

  • Facebook::Graph in Perl or fb_graph gem in Ruby. (OAuth API)

    I can't even authenticate. Both of these are geared towards web rather than desktop applications of OAuth, but I think I ought to be able to do:

    my $fb = Facebook::Graph->new(
     app_id => "xxx",
     secret => "yyy",
     postback => "https://www.facebook.com/connect/login_success.html"
    );
    print $fb->authorize->extend_permissions(qw(publish_stream read_stream))->uri_as_string;
    

    Go to that URL in my browser, capture the code parameter returned, and then

    my $r = $fb->request_access_token($code);
    

    Unfortunately:

    Could not fetch access token: Bad Request at /Library/Perl/5.16/Facebook/Graph/AccessToken/Response.pm line 26
    
  • Similarly in Ruby, using fb_graph,

    fb_auth = FbGraph::Auth.new(APP_ID, APP_SECRET)
    
    client = fb_auth.client
    client.redirect_uri = "https://www.facebook.com/connect/login_success.html"
    puts client.authorization_uri(
      :scope => [:publish_stream, :read_stream]
    )
    

    Gives me a URL which returns a code, but running

    client.authorization_code = <code>
    FbGraph.debug!
    access_token = client.access_token!
    

    returns

    {
      "error": {
        "message": "Missing client_id parameter.",
        "type":    "OAuthException",
        "code":    101
      }
    }
    

    Update: When I change the access_token! call to access_token!("foobar") to force Rack::OAuth2::Client to put the identifier and secret into the request body, I get the following error instead:

    {
      "error": {
        "message": "The request is invalid because the app is configured as a desktop app",
         "type":   "OAuthException",
         "code":   1
      }
    }
    

How am I supposed to authenticate a desktop/command line app to Facebook using OAuth?

like image 285
Simon Cozens Avatar asked Feb 24 '14 04:02

Simon Cozens


People also ask

How do I get my Facebook business manager access token?

Navigate to Business Settings > Users > System Users > System User Name (where System User Name is the actual name of your System User). Click on Generate New Token and select the newly created app.

How do I fix an invalid access token on Facebook?

Delete the history and cookies in your browser. Directly log into Facebook or into your Facebook Business Manager account. You should then be prompted through steps that will re-authorize and unblock your account. Once you have completed the necessary steps the account will be unblocked.


2 Answers

So, I finally got it working, without setting up a web server and doing a callback. The trick, counter-intuitively, was to turn off the "Desktop application" setting and not to request offline_access.

FaceBook::Graph's support for posting videos doesn't seem to work at the moment, so I ended up doing it in Ruby.

fb_auth = FbGraph::Auth.new(APP_ID, APP_SECRET)

client = fb_auth.client
client.redirect_uri = "https://www.facebook.com/connect/login_success.html"

if ARGV.length == 0
  puts "Go to this URL"
  puts client.authorization_uri(:scope => [:publish_stream, :read_stream] )
  puts "Then run me again with the code"
  exit
end

if ARGV.length == 1
  client.authorization_code = ARGV[0]
  access_token = client.access_token! :client_auth_body
  File.open("authtoken.txt", "w") { |io| io.write(access_token)  }
  exit
end

file, title, description = ARGV

access_token = File.read("authtoken.txt")
fb_auth.exchange_token! access_token
File.open("authtoken.txt", "w") { |io| io.write(fb_auth.access_token)  }

me = FbGraph::Page.new(PAGE_ID, :access_token => access_token)
me.video!(
    :source => File.new(file),
    :title => title,
    :description => description
)
like image 71
Simon Cozens Avatar answered Oct 28 '22 01:10

Simon Cozens


Problem is in your case that for OAuth you'll need some endpoint URL which is publicly reachable over the Internet for Facebook servers, which can be a no-go for normal client PCs, or a desktop application which is capable of WebViews (and I assume, command line isn't).

Facebook states at https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow#login that you can build a desktop client login flow, but only via so-called WebViews. Therefore, you'd need to call the OAuth endpoint like this:

https://www.facebook.com/dialog/oauth?client_id={YOUR_APP_ID}&redirect_uri=https://www.facebook.com/connect/login_success.html&response_type=token&scope={YOUR_PERMISSION_LIST}

You then have to inspect the resulting redirected WebView URL as quoted:

When using a desktop app and logging in, Facebook redirects people to the redirect_uri mentioned above and places an access token along with some other metadata (such as token expiry time) in the URI fragment:

https://www.facebook.com/connect/login_success.html#access_token=ACCESS_TOKEN... 

Your app needs to detect this redirect and then read the access token out of the URI using the mechanisms provided by the OS and development framework you are using.

If you want to do this in "hacking mode", I'd recommend to do the following.:

  • As you want to post to a Page, get a Page Access Token and store it locally. This can be done by using the Graph Explorer at the

https://developers.facebook.com/tools/explorer?method=GET&path=me%2Faccounts

endpoint. Remember to give "manage_pages" and "publish_actions" permissions.

  • Use cURL (http://curl.haxx.se/docs/manpage.html) to POST the videos to the Graph API with the Access Token and the appropriate Page ID you acquired in step 1 like the following:

curl -v -0 --form title={YOUR_TITLE} --form description={YOUR_DESCRIPTION} --form source=@{YOUR_FULL_FILE_PATH} https://graph-video.facebook.com/{YOUR_PAGE_ID}/videos?access_token={YOUR_ACCESS_TOKEN}

References:

https://developers.facebook.com/docs/graph-api/reference/page/videos/#publish https://developers.facebook.com/docs/reference/api/video/

like image 30
Tobi Avatar answered Oct 28 '22 02:10

Tobi