Obtaining a Facebook auth token for a command-line (desktop) application
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
)
Trying to authenticate and read newsfeed/timeline (C# Desktop application)
In general, it is quite hard to authenticate a User in a desktop application. Have a look at my answer to the question Obtaining a Facebook auth token for a command-line (desktop) application The only chance is using a WebView.
It is possible to exchange short-lived Access Tokens into long-lived ones: https://developers.facebook.com/docs/facebook-login/access-tokens/#extending
Concerning your questions:
- Yes, but only in a way as descibed in my answer linked above
You can use the following endpoints, depending on what you want to achieve:
- Feed (with it's filtered versions) https://developers.facebook.com/docs/graph-api/reference/user/feed/
- Home https://developers.facebook.com/docs/graph-api/reference/user/home/
How to generate Facebook User Access Token using curl
You can´t get ANY Token without an App, but you don´t need to program anything in order to get a User Token. These articles explain everything in detail:
- https://developers.facebook.com/docs/facebook-login/access-tokens
- http://www.devils-heaven.com/facebook-access-tokens/
- https://developers.facebook.com/docs/facebook-login/
For example, you can use the API Explorer to select your App and generate User Tokens.
How to authenticate facebook command line app (Ruby)
This isn't currently possible with Open Graph applications without sharing a server-side authentication token. Facebook requires you maintain control (and not share) your Applications authentication token. If a user were to abuse the command line application, and make a large number of requests to the server, using your app ID and token, you would be the one on the hook.
The best way to accomplish your goal is with a server under your control in between your command line application and the Facebook graph api. The command-line api could direct the user to your website where they would hit the "Facebook Connect" button. The user would authenticate the application with your server, and you could provide them with a token they could pair with their user ID to post status updates or retrieve friends through your server.
The command-line api would interact with your server, and your server with the Facebook Graph API.
A strong side benefit of this approach is that if Facebook's API changes, your clients would not break (no need to change your own server's API).
Facebook Authentication for Desktop (Console based) application
Maybe you can have some setup process where you obtain the tokens with offline access, that way the user will need to be presented with facebook login page only once, then you use this token later with the console app.
See offline_access on http://developers.facebook.com/docs/authentication/permissions/
Facebook Access Token - Automate Getting the Token
This code will automate the retrieval of the access_token. You must have credentials to the account you are requesting an access token for.
Updated
First login to the facebook account.
// LOG INTO FACEBOOK ACCT
string email = "youremail@blah.com";
string pw = "yourPassWord";
CookieContainer cookieJar = new CookieContainer();
HttpWebRequest request1 = (HttpWebRequest)WebRequest.Create("https://www.facebook.com");
request1.CookieContainer = cookieJar;
request1.UserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36";
//Get the response from the server and save the cookies from the first request..
HttpWebResponse response = (HttpWebResponse)request1.GetResponse();
var cookies = response.Cookies;
cookieJar.Add(cookies);
response.Close();// close the response
string getUrl = "https://www.facebook.com/login.php?login_attempt=1";
string postData = String.Format("email={0}&pass={1}", email, pw);
HttpWebRequest getRequest = (HttpWebRequest)WebRequest.Create(getUrl);
getRequest.CookieContainer = cookieJar;
//Adding Previously Received Cookies
getRequest.CookieContainer.Add(cookies);
getRequest.Method = WebRequestMethods.Http.Post;
getRequest.UserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36";
getRequest.AllowWriteStreamBuffering = true;
getRequest.ProtocolVersion = HttpVersion.Version11;
getRequest.AllowAutoRedirect = true;
getRequest.ContentType = "application/x-www-form-urlencoded";
byte[] byteArray = Encoding.ASCII.GetBytes(postData);
getRequest.ContentLength = byteArray.Length;
Stream newStream = getRequest.GetRequestStream(); //open connection
newStream.Write(byteArray, 0, byteArray.Length); // Send the data.
newStream.Close();
HttpWebResponse getResponse = (HttpWebResponse)getRequest.GetResponse();
using (StreamReader sr = new StreamReader(getResponse.GetResponseStream()))
{
string sourceCode = sr.ReadToEnd();
}
Then request the access_token
ApplicationId = request.ClientId; // your application id
string permissions = "['ads_management', 'ads_read']";
var destinationURL = String.Format(
@"https://www.facebook.com/dialog/oauth?client_id={0}&scope={1}&redirect_uri=http://www.kb-demos.com/login_success.html&response_type=token",
ApplicationId,
permissions);
// Create a new 'HttpWebRequest' Object to the mentioned URL.
HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(destinationURL);
// use the same cookie container and cookies
myHttpWebRequest.CookieContainer = cookieJar;
myHttpWebRequest.CookieContainer.Add(cookies); //recover cookies First request
myHttpWebRequest.UserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36";
myHttpWebRequest.AllowAutoRedirect = false;
// Assign the response object of 'HttpWebRequest' to a 'HttpWebResponse' variable.
HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
Console.WriteLine("\nThe Request HttpHeaders are \n\n\tName\t\tValue\n{0}", myHttpWebRequest.Headers); // my http headers
Console.WriteLine("\nThe Request HttpHeaders are \n\n\tName\t\tValue\n{0}", myHttpWebRequest.CookieContainer); // my http headers
//Console.WriteLine("\nThe Request HttpHeaders are \n\n\tName\t\tValue\n{0}", cookies); // my http headers
var headers = myHttpWebResponse.Headers;
// output all the headers
foreach (var header in headers)
{
Console.WriteLine(header.ToString() + ": " + headers[header.ToString()] + "\n");
}
var cow = GetParams(headers["Location"]);
string accessToken = "";
accessToken = cow["#access_token"];
And the helper method
/// <summary>
/// Helper method to get Params from URL using RegEx
/// </summary>
static Dictionary<string, string> GetParams(string uri)
{
var matches = Regex.Matches(uri, @"[\?&](([^&=]+)=([^&=#]*))", RegexOptions.Compiled);
return matches.Cast<Match>().ToDictionary(
m => Uri.UnescapeDataString(m.Groups[2].Value),
m => Uri.UnescapeDataString(m.Groups[3].Value)
);
}
Long-lasting FB access-token for server to pull FB page info
These are the steps that were previously in the question - they have been migrated to this answer.
Having found that it is possible to generate a Facebook Page Access Token that does not expire (with help from @Igy), here is a clear, step-by-step quide for all those looking to the same:
- Make sure you are the admin of the FB page you wish to pull info from
- Create a FB App (should be with the same user account that is the page admin)
- Head over to the Facebook Graph API Explorer
- On the top right, select the FB App you created from the "Application" drop down list
- Click "Get Access Token"
- Make sure you add the
manage_pages
permission - Convert this short-lived access token into a long-lived one by making this Graph API call:
https://graph.facebook.com/oauth/access_token?client_id=<your FB App ID >&client_secret=<your FB App secret>&grant_type=fb_exchange_token&fb_exchange_token=<your short-lived access token>
- Grab the new long-lived access token returned back
- Make a Graph API call to see your accounts using the new long-lived access token:
https://graph.facebook.com/me/accounts?access_token=<your long-lived access token>
- Grab the
access_token
for the page you'll be pulling info from - Lint the token to see that it is set to
Expires: Never
!
That should do it. You should now have a Facebook Page Access Token that doesn't expire, unless:
- You change your Facebook account password
- You lose admin access for the target page
- You delete or de-authorize your Facebook App
Any of these will cause the access token to become invalid.
If you are getting (#100) Tried accessing nonexisting field (accounts) on node type (Page)
, go to the Access Token Debugger, copy the value of User ID
, and use it to replace the "me" part of the URL in step 9.
Related Topics
How to Write an Rspec Test for a Ruby Method That Contains "Gets.Chomp"
How to Get a Selenium/Ruby Bot to Wait Before Performing an Action
Stop Loading Page Watir-Webdriver
Accepts_Nested_Attributes_For Ignore Blank Values
Wrapping Text into Lines at Word Boundaries
Call Ruby Script from Powershell
Ruby: Ssl_Connect Syscall Returned=5 Errno=0 State=Unknown State (Openssl::Ssl::Sslerror)
Import SASS File from Database Instead of Filesystem
How to Run Ruby on Rails Applications on a Windows Box
Ruby Pipes: How to Tie the Output of Two Subprocesses Together
How to Convert a Ruby String with Brackets to an Array
No Such File to Load -- SQLite3/Sqlite3_Native
How to Split Routes.Rb into Smaller Files
Ruby What Class Gets a Method When There Is No Explicit Receiver