I have a web application that runs a schedule job which pulls in the Facebook reviews from a page which I manage. Here is a snippet
public void Execute(IJobExecutionContext context)
{
//get api details from the web.config
var pageId = WebConfigurationManager.AppSettings["FacebookPageId"];
var token = WebConfigurationManager.AppSettings["FacebookAPIToken"];
if (!string.IsNullOrEmpty(token))
{
//create a facebook client object
var client = new FacebookClient(token);
//make a call to facebook to retrieve the json data
dynamic graphJson = client.Get(pageId + "?fields=ratings{review_text,reviewer,rating}").ToString();
//deserialize the json returned from facebook
ReviewDeserializeData reviews = JsonConvert.DeserializeObject<ReviewDeserializeData>(graphJson);
//loop through the deserialized data and pass each review to the import class
foreach (var rating in reviews.ratings.data)
{
var fbRating = new FacebookRating
{
RatingReviewerId = long.Parse(rating.reviewer.id),
StarRating = rating.rating,
ReviewerName = rating.reviewer.name,
ReviewText = rating.review_text
};
ImportFacebookRating.ImportTheFacebookRating(fbRating);
}
}
}
This works great until the Page Access Token expires. I have tried following many articles such as this one https://medium.com/#Jenananthan/how-to-create-non-expiry-facebook-page-token-6505c642d0b1#.24vb5pyiv but i have had no luck fixing the token expiring.
Does anyone know how i can achieve this or is there a way to programmatically generate a new token if the existing one has expired? at the moment i have it stored in the web.config as an app setting.
Thanks
I found the answer here and was able to generate a token that 'Never' Expires Long-lasting FB access-token for server to pull FB page info
Related
I am using TweetSharp to send tweets to users (currently testing it) however it keeps coming back with Bad Authentication Data
{"errors":[{"code":215,"message":"Bad Authentication data."}]}
I have checked my app settings and it has full read and write access. I have also tried to regenerate my consumer keys but still not luck.
here is my code
public ActionResult AccessToken()
{
string oauth_consumer_key = "<consumer key>";
string oauth_consumer_secret = "<consumer secret>";
var service = new TwitterService(oauth_consumer_key, oauth_consumer_secret);
// Now we need the Token and TokenSecret
OAuthRequestToken requestToken = service.GetRequestToken("http://localhost:37808/");
string authURL = service.GetAuthorizationUri(requestToken).ToString();
Process.Start(authURL);
SendTweetOptions options = new SendTweetOptions();
options.Status = "Hello there Twitter";
service.SendTweet(options);
var re = service.Response.Response;
return View();
}
Am I doing anything wrong?
Finally solved the issue and it works well. Based upon comments from Yort.
public ActionResult AccessToken()
{
// Step 1 - Retrieve an OAuth Request Token
TwitterService service = new TwitterService(ConfigurationManager.AppSettings["TwitterConsumerKey"], ConfigurationManager.AppSettings["TwitterConsumerSecret"]);
// This is the registered callback URL
OAuthRequestToken requestToken = service.GetRequestToken("http://localhost:37808/Twitter/OToken");
// Step 2 - Redirect to the OAuth Authorization URL
Uri uri = service.GetAuthorizationUri(requestToken);
return new RedirectResult(uri.ToString(), false /*permanent*/);
//return View();
}
public ActionResult OToken()
{
return View();
}
public ActionResult UserInfo(string oauth_token, string oauth_verifier)
{
var requestToken = new OAuthRequestToken { Token = oauth_token };
// Step 3 - Exchange the Request Token for an Access Token
TwitterService service = new TwitterService(ConfigurationManager.AppSettings["TwitterConsumerKey"],
ConfigurationManager.AppSettings["TwitterConsumerSecret"]);
OAuthAccessToken accessToken = service.GetAccessToken(requestToken, oauth_verifier);
// Step 4 - User authenticates using the Access Token
service.AuthenticateWith(accessToken.Token, accessToken.TokenSecret);
TwitterUser user = service.VerifyCredentials(new VerifyCredentialsOptions());
ViewBag.Message = string.Format("{0}", user.ScreenName);
// Step 5 - Send Tweet to User TimeLine
SendTweetOptions options = new SendTweetOptions();
string URL = "file:\\C:\\Users\\<User>\\Desktop\\test.jpg";
string path = new Uri(URL).LocalPath;
// Sending with Media
using (var stream = new FileStream(path, FileMode.Open))
{
service.SendTweetWithMedia(new SendTweetWithMediaOptions
{
Status = "<status>",
Images = new Dictionary<string, Stream> { { path, stream } }
});
}
var responseText = service.Response.StatusCode;
if (responseText.ToString() == "OK")
{
ViewBag.Message = "Tweet Successful";
}
else
{
ViewBag.Message = "Tweet Unsuccessful";
}
return View();
}
}
I don't believe you can send Tweets as just a consumer, the Tweets have to be "owned" by a user account. You need to register a Twitter account, then do the full oauth authentication process to get an access token (in addition to the consumer token), then reauthorise the TweetSharp service using both tokens.
Your code above nearly gets there (I think). After the Process.start call there needs to be logic to use the verifier returned in the browser (a number displayed after the user logs in) to complete the auth process and act as that user. At the moment, your code gets half way through that process but does not complete it, so when you try to tweet your TweetSharp service is only authed as the app and not the user.
The originalTweetSharp readme.md does include the missing bits of code. Step 3 needs the actual verifier returned in the browser after login:
// Step 3 - Exchange the Request Token for an Access Token
string verifier = "123456"; // <-- This is input into your application by your user
OAuthAccessToken access = service.GetAccessToken(requestToken, verifier);
// Step 4 - User authenticates using the Access Token
service.AuthenticateWith(access.Token, access.TokenSecret);
//Now your tweet call should work here.
It also looks like you're doing this in a web app on the server? In which case you're using entirely the wrong oauth flow (I believe). This one is designed for desktop apps, hence the call that starts a new browser process for the user to login with. I'm not entirely sure how the web flow works as I've never used it, but I believe you need to redirect the user to the authorisation url you receive, and the callback registered with Twitter should point back to your site. I think there is some kind of state parameter that can be passed back through the oauth flow so you can implement your own logic to pickup where you left off based on a session id or similar.
I worked on this subject before. You have to developer account before the send tweet because you need tokens and keys. It's my windows service project.
I wrote my tokens and key codes in App.config
<appSettings>
<add key="twitterAccessToken" value="*****"/>
<add key="twitterAccessTokenSecret" value="*****"/>
<add key="twitterConsumerKey" value="*****"/>
<add key="twitterConsumerSecret" value="*****"/>
public static void SendTweet()
{
try
{
GetPixelImageFile();
string key = ConfigurationSettings.AppSettings.Get("twitterConsumerKey");
string secret = ConfigurationSettings.AppSettings.Get("twitterConsumerSecret");
string token = ConfigurationSettings.AppSettings.Get("twitterAccessToken");
string tokenSecret = ConfigurationSettings.AppSettings.Get("twitterAccessTokenSecret");
string message = "Color, Colorful, Pixel, Art, PixelColouring, Follow";
var service = new TweetSharp.TwitterService(key, secret);
service.AuthenticateWith(token, tokenSecret);
using (var stream = new FileStream(#"C:\Images\Pixel.png", FileMode.Open))
{
var result = service.SendTweetWithMedia(new SendTweetWithMediaOptions
{
Status = message,
Images = new Dictionary<string, Stream> { { "john", stream } }
});
SendMail("SendTweet", (result == null ? "" : result.Text));
}
}
catch (Exception ex)
{
SendMail("SendTweet", ex.Message);
}
}
I have created a facebook page and a facebook application for my website and now I need to post messages onto the facebook page with help of facebook SDK .NET.
This is what I got so far :
public static bool UploadPost(string message)
{
dynamic result;
//https://developers.facebook.com/tools/explorer/
//https://developers.facebook.com/tools/access_token/
FacebookClient client = new FacebookClient("secret access token");
result = client.Get("oauth/access_token", new
{
client_id = "[Client ID number]",
client_secret = "[Client sercret",
grant_type = "client_credentials",
});
result = client.Post("[facebook app Id]/feed", new { message = "Test Message from app" });
//result.id;
result = client.Get("[facebook app Id]");
return false;
}
When running this I get : Additional information: (OAuthException - #200) (#200) The user hasn't authorized the application to perform this action on client.Post. If I remove the client.Post row every thing works good, the correct data is fetched.
I have tried follow some helps on facebook SDK .NET website but it is still not working.
The main problem now is that I get permission exception. I was hoping that my facebook app hade enouth permissions to publish post from my website to the facebook page.
Here is a step wise tutorial to register your application with facebook and get an app Id for your application.
Then for permissions ::
private const string ExtendedPermissions = "user_about_me,read_stream,publish_stream";
This is a string of permissions. Pass it on further for getting correct permissions to post messages on page. Post using your standard code for posting no FB pages.
Cheers. Hope it helps.
Are you trying to post to [facebook app id]?
I would recomend to post to "me/feed" and test if that works.
Also, to post to Facebook you have to have the publish_stream permission
private async Task Authenticate()
{
string message = String.Empty;
try
{
session = await App.FacebookSessionClient.LoginAsync("user_about_me,read_stream,publish_actions");
App.AccessToken = session.AccessToken;
App.FacebookId = session.FacebookId;
Dispatcher.BeginInvoke(() => NavigationService.Navigate(new Uri("/Pages/LandingPage.xaml", UriKind.Relative)));
}
catch (InvalidOperationException e)
{
message = "Login failed! Exception details: " + e.Message;
MessageBox.Show(message);
}
}
Should work :)
The following should work.
var fb = new FacebookClient("access_token");
fb.PostCompleted += (o, e) => {
if(e.Error == null) {
var result = (IDictionary<string, object>)e.GetResultData();
var newPostId = (string)result.id;
}
};
var parameters = new Dictionary<string, object>();
parameters["message"] = "My first wall post using Facebook SDK for .NET";
fb.PostAsync("me/feed", parameters);
This was taken directly from the documentation.
By creating a extended page token and use it to make the post everything works just fine. See this : How to get Page Access Token by code?
Im surprised that this simple task was so hard to get running and that there was vary little help to get.
I have a question regarding using facebook graph API (OAuth) to upload photo.
I have created one company page under my account.
When I use my account to upload photo to my company page, my user name appears as a user who uploaded the page.
Is there anyway I can upload page so that company name appears?
Below is the code that I currently implemented.
string access_token = FacebookSystem.RetrieveToken(UserEmail, AppID);
string query = string.Empty;
if (string.IsNullOrEmpty(PageID) || PageID.Equals("default", StringComparison.InvariantCultureIgnoreCase))
{
query = "me/photos";
}
else
{
query = string.Format("{0}/photos", PageID);
}
var fb = new FacebookClient(access_token);
try
{
dynamic parameters = new ExpandoObject();
foreach (string i in args.FileList)
{
parameters.message = args.Comment;
parameters.source = new FacebookMediaObject
{
ContentType = "image",
FileName = Path.GetFileName(i)
}.SetValue(File.ReadAllBytes(i));
fb.Post(query, parameters);
}
}
in order to use Graph API on behalf of a Page, you need to get Page access token - see here for more details: https://developers.facebook.com/docs/facebook-login/access-tokens/#pagetokens
Authenticate the user and request the manage_pages permission
Get the list of pages the user manages from (1): https://graph.facebook.com/me/accounts?access_token=USER_ACCESS_TOKEN
Parse the list and get the token - and use it to post to the feed.
you will do (1) in graph API explorer - and you will get user token. Then insert that token into URL in (2) - and you will see all your pages and corresponding token. Take the one you need and use it in your C# code to upload images.
I'm using Facebook C# sdk with the code,
i'm trying to create a new score for a user
but i get this error:
(OAuthException) An active access token must be used to query information about the current user.
what am i missing?
protected void btnAddScore_Click(object sender, EventArgs e)
{
if (CanvasAuthorizer.Authorize())
{
var fb = new FacebookWebClient();
dynamic parameters = new ExpandoObject();
parameters.score = 77;
parameters.access_token = GetAppAccessToken();
try
{
dynamic id = fb.Post("me/scores", parameters);
lblPostMessageResult.Text = "Message posted successfully";
txtMessage.Text = string.Empty;
}
catch (FacebookApiException ex)
{
lblPostMessageResult.Text = ex.Message;
}
}
}
private string GetAppAccessToken()
{
var oauthClient = new FacebookOAuthClient
{
AppId = FacebookWebContext.Current.Settings.AppId,
AppSecret = FacebookWebContext.Current.Settings.AppSecret
};
dynamic result = oauthClient.GetApplicationAccessToken();
string appAccessToken = result.access_token;
return appAccessToken;
}
edit:
I got the answer form here:
http://facebooksdk.codeplex.com/discussions/279307
the new right code is:
if (CanvasAuthorizer.Authorize())
{
var fb = new FacebookClient(CanvasAuthorizer.FacebookWebRequest.AccessToken);
var oauthClient = new FacebookOAuthClient(FacebookApplication.Current);
dynamic parameters = new ExpandoObject();
parameters.score = 100;
dynamic ac = oauthClient.GetApplicationAccessToken();
parameters.access_token = ac.access_token;
dynamic result = fb.Post(CanvasAuthorizer.FacebookWebRequest.UserId + "/scores", parameters);
}
Answer:-
Actually for using SCORE Graph API you need the "Application access token" which is different than a normal access token
So if you want your task to be done GET an Application access token by using the following script.......
And then replace the generated application_access_token with old access_token, that's it
The below code is written in php try convert it in c# and then apply it
$APPLICATION_ID = "APP_ID";
$APPLICATION_SECRET = "APP_SECRET";
$token_url = "https://graph.facebook.com/oauth/access_token?" .
"client_id=" . $APPLICATION_ID .
"&client_secret=" . $APPLICATION_SECRET .
"&grant_type=client_credentials";
$app_token = file_get_contents($token_url);
After getting this application access token you can easily do this task.
When You Need An Application Access Token
You need to use a Facebook application access token when you have a process that acts on behalf of the application, rather than on behalf of a particular user. This happens when you access your Facebook Insights data for your app via the graph, and also when you want to create test Facebook users for your app.
Sadly, the documentation for this is buried in the authentication guide for the Facebook graph API.
Your application need to take "publish_actions" permission from user to update the score.
Refer to Create or update a score for a user section of the below documentation.
https://developers.facebook.com/docs/score/
I'm trying to use the Google+ API to access info for the authenticated user. I've copied some code from one of the samples, which works fine (below), however I'm having trouble making it work in a way I can reuse the token across app-launches.
I tried capturing the "RefreshToken" property and using provider.RefreshToken() (amongst other things) and always get a 400 Bad Request response.
Does anyone know how to make this work, or know where I can find some samples? The Google Code site doesn't seem to cover this :-(
class Program
{
private const string Scope = "https://www.googleapis.com/auth/plus.me";
static void Main(string[] args)
{
var provider = new NativeApplicationClient(GoogleAuthenticationServer.Description);
provider.ClientIdentifier = "BLAH";
provider.ClientSecret = "BLAH";
var auth = new OAuth2Authenticator<NativeApplicationClient>(provider, GetAuthentication);
var plus = new PlusService(auth);
plus.Key = "BLAH";
var me = plus.People.Get("me").Fetch();
Console.WriteLine(me.DisplayName);
}
private static IAuthorizationState GetAuthentication(NativeApplicationClient arg)
{
// Get the auth URL:
IAuthorizationState state = new AuthorizationState(new[] { Scope });
state.Callback = new Uri(NativeApplicationClient.OutOfBandCallbackUrl);
Uri authUri = arg.RequestUserAuthorization(state);
// Request authorization from the user (by opening a browser window):
Process.Start(authUri.ToString());
Console.Write(" Authorization Code: ");
string authCode = Console.ReadLine();
Console.WriteLine();
// Retrieve the access token by using the authorization code:
return arg.ProcessUserAuthorization(authCode, state);
}
}
Here is an example. Make sure you add a string setting called RefreshToken and reference System.Security or find another way to safely store the refresh token.
private static byte[] aditionalEntropy = { 1, 2, 3, 4, 5 };
private static IAuthorizationState GetAuthorization(NativeApplicationClient arg)
{
// Get the auth URL:
IAuthorizationState state = new AuthorizationState(new[] { PlusService.Scopes.PlusMe.GetStringValue() });
state.Callback = new Uri(NativeApplicationClient.OutOfBandCallbackUrl);
string refreshToken = LoadRefreshToken();
if (!String.IsNullOrWhiteSpace(refreshToken))
{
state.RefreshToken = refreshToken;
if (arg.RefreshToken(state))
return state;
}
Uri authUri = arg.RequestUserAuthorization(state);
// Request authorization from the user (by opening a browser window):
Process.Start(authUri.ToString());
Console.Write(" Authorization Code: ");
string authCode = Console.ReadLine();
Console.WriteLine();
// Retrieve the access token by using the authorization code:
var result = arg.ProcessUserAuthorization(authCode, state);
StoreRefreshToken(state);
return result;
}
private static string LoadRefreshToken()
{
return Encoding.Unicode.GetString(ProtectedData.Unprotect(Convert.FromBase64String(Properties.Settings.Default.RefreshToken), aditionalEntropy, DataProtectionScope.CurrentUser));
}
private static void StoreRefreshToken(IAuthorizationState state)
{
Properties.Settings.Default.RefreshToken = Convert.ToBase64String(ProtectedData.Protect(Encoding.Unicode.GetBytes(state.RefreshToken), aditionalEntropy, DataProtectionScope.CurrentUser));
Properties.Settings.Default.Save();
}
The general idea is as follows:
You redirect the user to Google's Authorization Endpoint.
You obtain a short-lived Authorization Code.
You immediately exchange the Authorization Code for a long-lived Access Token using Google's Token Endpoint. The Access Token comes with an expiry date and a Refresh Token.
You make requests to Google's API using the Access Token.
You can reuse the Access Token for as many requests as you like until it expires. Then you can use the Refresh Token to request a new Access Token (which comes with a new expiry date and a new Refresh Token).
See also:
The OAuth 2.0 Authorization Protocol
Google's OAuth 2.0 documentation
I also had problems with getting "offline" authentication to work (i.e. acquiring authentication with a refresh token), and got HTTP-response 400 Bad request with a code similar to the OP's code. However, I got it to work with the line client.ClientCredentialApplicator = ClientCredentialApplicator.PostParameter(this.clientSecret); in the Authenticate-method. This is essential to get a working code -- I think this line forces the clientSecret to be sent as a POST-parameter to the server (instead of as a HTTP Basic Auth-parameter).
This solution assumes that you've already got a client ID, a client secret and a refresh-token. Note that you don't need to enter an access-token in the code. (A short-lived access-code is acquired "under the hood" from the Google server when sending the long-lived refresh-token with the line client.RefreshAuthorization(state);. This access-token is stored as part of the auth-variable, from where it is used to authorize the API-calls "under the hood".)
A code example that works for me with Google API v3 for accessing my Google Calendar:
class SomeClass
{
private string clientID = "XXXXXXXXX.apps.googleusercontent.com";
private string clientSecret = "MY_CLIENT_SECRET";
private string refreshToken = "MY_REFRESH_TOKEN";
private string primaryCal = "MY_GMAIL_ADDRESS";
private void button2_Click_1(object sender, EventArgs e)
{
try
{
NativeApplicationClient client = new NativeApplicationClient(GoogleAuthenticationServer.Description, this.clientID, this.clientSecret);
OAuth2Authenticator<NativeApplicationClient> auth = new OAuth2Authenticator<NativeApplicationClient>(client, Authenticate);
// Authenticated and ready for API calls...
// EITHER Calendar API calls (tested):
CalendarService cal = new CalendarService(auth);
EventsResource.ListRequest listrequest = cal.Events.List(this.primaryCal);
Google.Apis.Calendar.v3.Data.Events events = listrequest.Fetch();
// iterate the events and show them here.
// OR Plus API calls (not tested) - copied from OP's code:
var plus = new PlusService(auth);
plus.Key = "BLAH"; // don't know what this line does.
var me = plus.People.Get("me").Fetch();
Console.WriteLine(me.DisplayName);
// OR some other API calls...
}
catch (Exception ex)
{
Console.WriteLine("Error while communicating with Google servers. Try again(?). The error was:\r\n" + ex.Message + "\r\n\r\nInner exception:\r\n" + ex.InnerException.Message);
}
}
private IAuthorizationState Authenticate(NativeApplicationClient client)
{
IAuthorizationState state = new AuthorizationState(new string[] { }) { RefreshToken = this.refreshToken };
// IMPORTANT - does not work without:
client.ClientCredentialApplicator = ClientCredentialApplicator.PostParameter(this.clientSecret);
client.RefreshAuthorization(state);
return state;
}
}
The OAuth 2.0 spec is not yet finished, and there is a smattering of spec implementations out there across the various clients and services that cause these errors to appear. Mostly likely you're doing everything right, but the DotNetOpenAuth version you're using implements a different draft of OAuth 2.0 than Google is currently implementing. Neither part is "right", since the spec isn't yet finalized, but it makes compatibility something of a nightmare.
You can check that the DotNetOpenAuth version you're using is the latest (in case that helps, which it might), but ultimately you may need to either sit tight until the specs are finalized and everyone implements them correctly, or read the Google docs yourself (which presumably describe their version of OAuth 2.0) and implement one that specifically targets their draft version.
I would recommend looking at the "SampleHelper" project in the Samples solution of the Google .NET Client API:
Samples/SampleHelper/AuthorizationMgr.cs
This file shows both how to use Windows Protected Data to store a Refresh token, and it also shows how to use a Local Loopback Server and different techniques to capture the Access code instead of having the user enter it manually.
One of the samples in the library which use this method of authorization can be found below:
Samples/Tasks.CreateTasks/Program.cs