tweetsharp - app stops being able to tweet after a few hours - c#

I have a asp.net 4.5 webforms site that allows users to link their account to twitter and tweet directly from my site.
My app is registered with twitter and I am able to successfully authorise my app for the user's account and initially can tweet fine, but after a few hours the tweets stop working. I am using tweetsharp to handle the authorisation.
my code is:
TwitterClientInfo twitterClientInfo = new TwitterClientInfo();
twitterClientInfo.ConsumerKey = ConsumerKey;
twitterClientInfo.ConsumerSecret = ConsumerSecret;
var requestToken = new OAuthRequestToken { Token = oauthtoken };
TwitterService twitterService = new TwitterService(ConsumerKey, ConsumerSecret);
OAuthAccessToken accessToken = twitterService.GetAccessToken(requestToken, oauthverifier);
twitterService.AuthenticateWith(accessToken.Token, accessToken.TokenSecret);
TwitterUser user = twitterService.VerifyCredentials(new VerifyCredentialsOptions());
SendTweetOptions options = new SendTweetOptions();
options.Status = tweetText;
twitterService.SendTweet(options);
what i have noticed is that while the app is successfully tweeting, the accessToken.Token value that is being used to authenticate the user has a proper value (a long string of numbers and upper/lowercase characters) however when it stops tweeting the accessToken.Token value is just a single question mark "?".
Twitter says it doesn't expire tokens so i am at a loss to understand what is happening or how it can be resolved? if i went in to my twitter account and deauthorised my app and went through the authorisation again it would work fine for a few hours, but obviously that's not something i can ask my users to do.
can anyone suggest a resolution to this - either to stop the accessToken value becoming ? or to handle it and get a proper value if it does (without reauthorising the app)

Well, without beginning to understand the actual issue, I managed to fix it
Instead of retrieving the access token every time via:
var requestToken = new OAuthRequestToken { Token = oauthtoken };
OAuthAccessToken accessToken = twitterService.GetAccessToken(requestToken, oauthverifier);
twitterService.AuthenticateWith(accessToken.Token, accessToken.TokenSecret);
i only do that once and store accessToken.Token and accessToken.TokenSecret in the database and retrieve them when tweeting and supply them
twitterService.AuthenticateWith(accessTokenFromDB, accessokenSecretFromDB);
I have seen somewhere that Twitter doesn't expire tokens, so this should work. Certainly it's been working for me all weekend whereas the original code would stop working after a few hours.
Thought this might help some others who have the same issue.

Related

How do I generate an assertion token for Sharepoint Access on behalf of another user in C#

I have a web application with a number of modules. One of the modules grabs a number of excel files from SharePoint directories, and then combines the data in them. So far, I have been just mapping the folders to OneDrive and accessing them that way. But this always uses my OneDrive credentials, which need to be refreshed from time to time. The right way to do this is to access them directly from Sharepoint on behalf of the user logged into my web application. I have the delegated API permission things set up in Azure, and I have the client ID and secret, etc.. I've been reading a number of articles on how to do this. All of them talk about how to get the token on behalf of someone else. These articles also talk about the assertion token needing to be passed in order to get the on behalf of token. However, they don't tell you how to get the assertion token in the first place. Here is the code I currently have:
'''var client = new RestClient("https://login.microsoftonline.com/XXXX/oauth2/v2.0/token");
var request = new RestRequest();
request.Method = Method.Post;
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddParameter("client_id", "MYCLIENTID", ParameterType.GetOrPost);
request.AddParameter("client_secret", "MYSECRET", ParameterType.GetOrPost);
request.AddParameter("scope", "https://MYTenent.sharepoint.com/.default", ParameterType.GetOrPost);
request.AddParameter("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer", ParameterType.GetOrPost);
request.AddParameter("requested_token_use", "on_behalf_of", ParameterType.GetOrPost);
RestResponse response = client.Execute(request);'''
The result of this is of course an error that the assertion was not supplied. I didn't supply any more code, because I can't even get passed this. The rest of my code takes the token and passes it to an auth provider, which is then used to instantiate the GraphServiceClient. Based on what I've read, that client is then used to get the lists, files, etc...
So, my question is, how do I get the assertion token in the first place? I'm hoping the code I have written so far is in the correct direction and all I'm missing is the assertion token.
UPDATE:
I've gotten one answer that really didn't help. I pretty much copied and pasted the code (replacing the clientID, etc..) and I received an error> I was going to copy and paste it from the solution comments provided in the answer, but I guess you can't do that while editing.
Someone also asked if I was able to get the auth code from the URL. The answer to that is no. We use 2 factor authentication, and I tried to manually look at the URLS as I was logging in, while using break points to slow things down a bit. And I did not see an auth code. I did put a break point directly after the line of code:
var info = await _signInManager.GetExternalLoginInfoAsync();
And when I look at the info variable, I can see 4 tokens. One of them is an access token and another is an ID token. The last one is an expiration date. I don't see an auth code, and from what I understand, by the time I see the access code, it's too late. The auth code was already used to get the access code.
UPDATE 2:
I know that OBO is not what I want. I also know that in order to use delegated permissions, I need to use the Auth Code flow and not client credentials. I can't seem to get the auth code from the users initial log in. And I don't know how to get it otherwise.
For those of you that might be thinking "Does he need to be spoon fed?", the answer is yes, I do. I need a simple code example that will get me the auth code, so I can use it in the rest of the code I already have. If anyone can paste that code into an answer and not provide a link, that would be great. I'm sorry, but the links I have been given, just go to microsoft learn sites that go through the explaination, but don't give any code samples.
The OBO flow is obviously not applicable in your context, and if you're going to get an access token on behalf of a logged in user, then you should focus on auth code flow or ROPC flow.
The corresponding C# code segment is:
using Microsoft.Graph;
using Azure.Identity;
var scopes = new[] { "https://{tenant-name}.sharepoint.com/.default" };
// Multi-tenant apps can use "common",
// single-tenant apps must use the tenant ID from the Azure portal
var tenantId = "tenant id";
// Values from app registration
var clientId = "client id";
var clientSecret = "client secret";
// For authorization code flow, the user signs into the Microsoft
// identity platform, and the browser is redirected back to your app
// with an authorization code in the query parameters
var authorizationCode = "authorization code ";
// using Azure.Identity;
var options = new TokenCredentialOptions
{
AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
};
// https://learn.microsoft.com/dotnet/api/azure.identity.authorizationcodecredential
var authCodeCredential = new AuthorizationCodeCredential(
tenantId, clientId, clientSecret, authorizationCode, options);
var accessToken = await authCodeCredential.GetTokenAsync(new Azure.Core.TokenRequestContext(scopes) { });
Console.WriteLine(accessToken.Token);
//var graphClient = new GraphServiceClient(authCodeCredential, scopes);

Did Facebook change completely change their SDK?

I've had a working application that connects and registers my users through their Facebook Accounts and retrieves some public information. Anyway, the application stopped working with Facebook with the new update (V2.6). I haven't changed any of my code, and now it's failing at creating a login URL for Facebook.
Last time I managed to Login successfully was on the 10th of April. I've read the Changelog for V2.6 but couldn't find anything that would/should change the Login flow. Here is the function that used to generate the Login URL and I would just get asked if I'd allow "my app" to access my Facebook information, I'd press allow and everything would continue perfectly. Now, I get the "SECURITY WARNING: Please treat the URL above as you would your password and do not share it with anyone. See the Facebook Help Centre for more information" error when the generated Login URL is called...
private string GenerateLoginUrlFacebook()
{
dynamic parameters = new ExpandoObject();
parameters.client_id = Globals.FBapplicationID;
parameters.redirect_uri = "https://www.facebook.com/connect/login_success.html";
parameters.response_type = "token";
parameters.display = "popup";
if (!string.IsNullOrWhiteSpace(Globals.FBextendedPermissionsNeeded))
parameters.scope = Globals.FBextendedPermissionsNeeded;
var fb = new FacebookClient();
Uri loginUri = fb.GetLoginUrl(parameters);
return loginUri.AbsoluteUri;
//return #"https://www.facebook.com/dialog/oauth?client_id=471150563090234&redirect_uri=https://www.facebook.com/connect/login_success.html";
}
Any help would be greatly appreciated!

Facebook's OAuth "Given URL is not permitted by the Application configuration"

I was working on this program that connects my users through their Facebook accounts. It's been working quiet stable for the past couple of weeks, and I was able to add more value to my program during that period. However, starting today I was unable to connect through Facebook as I usually do. Whenever I ask for App authorization (1st step) I get a "Given URL is not permitted by the Application configuration" error, Even tho i didn't change anything in my App Settings.
I looked everywhere to check if maybe Facebook did some Updates or something, but couldn't find anything. Last time i logged in successfully was the 30th of March.
How could have this happened if I didn't edit any of my code, and apparently Facebook didn't either! Any help would be greatly appreciated :)
private string GenerateLoginUrlFacebook()
{
dynamic parameters = new ExpandoObject();
parameters.client_id = Globals.FBapplicationID;
parameters.redirect_uri = "https://www.facebook.com/connect/login_success.html";
parameters.response_type = "token";
parameters.display = "popup";
if (!string.IsNullOrWhiteSpace(Globals.FBextendedPermissionsNeeded))
parameters.scope = Globals.FBextendedPermissionsNeeded;
var fb = new FacebookClient();
Uri loginUri = fb.GetLoginUrl(parameters);
return loginUri.AbsoluteUri;
}

Handle facebook expiration token

I am having some trouble while integrating facebook API with my desktop application.
Now, I`m trying to use Facebook SDK for .NET: http://facebooksdk.net/
Here is the problem:
When I use my tokens, Facebook returns the following message:
"Error validating access token: Session has expired at unix time 1365165488. The current unix time is 1378218499."
I saw in some posts that I can do something like this to renew my access token:
Dictionary<string, object> fbParams = new Dictionary<string, object> ();
fbParams["client_id"] = token.appId;
fbParams["grant_type"] = "fb_exchange_token";
fbParams["client_secret"] = token.appSecret;
fbParams["fb_exchange_token"] = token.accessToken;
JsonObject publishedResponse = fbClient.Get ("/oauth/access_token", fbParams) as JsonObject;
return publishedResponse["access_token"].ToString ();
But it doesn't work; it throws another exception with the same message ("Session has expired...")
Is there an easy way to do this?
I don't know if this can impact my application but this access token is like 1 year old (and I'm using in a desktop application).
Thank you very much! =)
The message is clear, you are using a token that has already expired (It's actually over four months old). You need to go back through the login flow with a user arriving at an authorization screen.
You cannot extend a token that has already expired, you can only extend tokens that are valid. e.g. a short lived (two hours) token to a long lived token (two months)

DotNetOpenAuth with Google Calendar Feed

I have been racking my brain for a few days trying to get a list of calendars from Google using DotNetOpenAuth.
I can successfully get a list of contacts using the DotNetOpenAuth Samples. I have integrated it with my domain using the OpenId+OAuth. Everything works great to get a list of contacts.
So from there I modified the code to try to retrieve a list of Calendars and I keep getting a 401 Unauthorized error.
I know it is authorizing because I can get the contact list. Does anyone have a code example how they are retrieving calendars or calendar events using the DotNetOpenAuth with Google???
Thanks
Update:
Thanks for the response. I have read everything I can get my hands on. Here is what I have done so far
Step 1: I created a new GetCalendarEndPoint in the GoogleConsumer.cs
private static readonly MessageReceivingEndpoint GetCalendarEndpoint = new MessageReceivingEndpoint("https://www.google.com/calendar/feeds/default", HttpDeliveryMethods.GetRequest);
Step 2: Next I created a new method GetCalendars patterned after the GetContacts Method in GoogleConsumer.cs - (Rebuilt the dll etc.)
public static XDocument GetCalendars(ConsumerBase consumer, string accessToken, int maxResults/* = 25*/, int startIndex/* = 1*/) {
if (consumer == null)
{
throw new ArgumentNullException("consumer");
}
var request = consumer.PrepareAuthorizedRequest(GetCalendarEndpoint, accessToken);
var response = consumer.Channel.WebRequestHandler.GetResponse(request);
string body = response.GetResponseReader().ReadToEnd();
XDocument result = XDocument.Parse(body);
return result;
Step 3: In my Application I modified the ScopeURI to the the Calendar URI from GoogleConsumer as follows
private IAuthenticationRequest GetGoogleRequest()
{
Realm realm = Request.Url.Scheme + Uri.SchemeDelimiter + Global.GoogleTokenManager.ConsumerKey + "/";
IAuthenticationRequest authReq = relyingParty.CreateRequest(GoogleOPIdentifier, realm);
// Prepare the OAuth extension
string scope = GoogleConsumer.GetScopeUri(GoogleConsumer.Applications.Calendar);
Global.GoogleWebConsumer.AttachAuthorizationRequest(authReq, scope);
// We also want the user's email address
var fetch = new FetchRequest();
fetch.Attributes.AddRequired(WellKnownAttributes.Contact.Email);
authReq.AddExtension(fetch);
return authReq;
}
However, when I run the app I get 401 Unauthorized when I make the following call
var calendars = GoogleConsumer.GetCalendars(Global.GoogleWebConsumer, State.GoogleAccessToken, 25, 1);
I have also checked that the State.GoogleAccess token exists by simply displaying it on my screen before I trigger the method that makes this call.
Again, if I exectute
var calendars = GoogleConsumer.GetContacs(Global.GoogleWebConsumer, State.GoogleAccessToken, 25, 1);
then it works??????? Thanks for you help.
I've been suffering through exactly the same thing for most of the weekend.
I think that after much fiddling with Fiddler I've found the cause and have a solution which, although not pretty, seems to work. I found that I was able to access the calendar feed by copying and pasting the DNOA-generated Uri into a browser, but always got a 401 when attempting programmatic access. This is apparently because the default auto-redirect behavior of HttpWebRequest discards any cookies that the redirect is attempting to set. The Contacts feed doesn't set any cookies during the redirect, so it is immune.
The first time you request a calendar feed (even with a properly constructed and signed OAuth request), Google replies with a redirect containing a cookie. If you don't present that "calendar cookie" at the same time as your feed request you will get a 401 Unauthorized when you attempt to follow the redirect to the feed.
here's the cookie-setting header from Google:
HTTP/1.1 302 Moved Temporarily
Set-Cookie: S=calendar=y7AlfgbmcqYl0ugrF-Zt9A;Expires=Tue, 10-Jan-2012 03:54:20 GMT;Secure
Here's what I'm doing to make it work:
// wc: WebConsumer
var calRequest = wc.PrepareAuthorizedRequest(erp2, authTokenRsp.AccessToken);
// need to stop redirect to capture calendar cookie token:
calRequest.AllowAutoRedirect = false;
var calResponse = calRequest.GetResponse();
var redirectCookie = calResponse.Headers[System.Net.HttpResponseHeader.SetCookie];
var cookiedCalRequest = wc.PrepareAuthorizedRequest(erp2, authTokenRsp.AccessToken);
cookiedCalRequest.Headers[System.Net.HttpRequestHeader.Cookie] = redirectCookie;
var calFeedResponse = cookiedCalRequest.GetResponse();
Have you read the Google Calendar data API documentation to make sure you have the right endpoints programmed in? Have you also modified the code that acquires the access token to request access to Google Calendar in addition to Google Contacts? The access token in the sample only gets Contacts permissions unless you change it.

Categories