I am trying to figure out if twitterizer is still relevant. The library looks really old. And the current project i am working on uses it. I am using the following code...
private static OAuthTokens OAuthTokens()
{
var accessToken = "<insert>";
var accessTokenSecret = "<insert>";
var consumerKey = "<insert>";
var consumerSecret = "<insert>";
return new OAuthTokens
{
ConsumerKey = consumerKey,
ConsumerSecret = consumerSecret,
AccessToken = accessToken,
AccessTokenSecret = accessTokenSecret
};
}
if i do the following call
var responseFollowersIds = TwitterFriendship.FollowersIds(credentials, new UsersIdsOptions()
{
UseSSL = true,
APIBaseAddress = "http://api.twitter.com/1.1/",
ScreenName = screenName
});
I can see that i have followers and that the request being made looks like this
https://api.twitter.com/1.1/followers/ids.json?screen_name=screenname&cursor=-1
notice that i set the APIBaseAddress to the latest version, but if i try and get the followers i use the following
var responseFollowers = TwitterFriendship.Followers(credentials, new FollowersOptions
{
ScreenName = screenName,
UseSSL = true,
APIBaseAddress = "http://api.twitter.com/1.1/",
});
But then i get an error
{"errors":[{"message":"Sorry, that page does not exist","code":34}]}
upon further investigation i realized that TwitterFriendship.Followers request url is wrong and that is buried deep in the twitterizer code.
The request made is
https://api.twitter.com/1.1/statuses/followers.json?cursor=-1&screen_name=screenname
and should be
https://api.twitter.com/1.1/followers/list.json
according to the new twitter documentation.
Is there an easy way to fix it?
A little bit late, but just in case anyone faces this problem again. You can easily fix it by modifiying the code of Twitterizer at \Methods\User\FollowersCommand.cs, look for the constructor and change the URL of the method:
public FollowersCommand(OAuthTokens tokens, FollowersOptions options)
: base(HTTPVerb.GET, "followers/list.json", tokens, options)
Related
I am developing an ASP.NET MVC app with Azure B2C authentication. It is required that, after the ID token expires (IIS session not expires), any subsequent action call should automatically refresh the ID token with the refresh token and then continue the execution without re-login.
Questions:
Does the solution make sense?
After refreshing the ID token and set the cookies, how can I redirect to the original url and continue execution without re-login?
Thanks, any idea is highly appreciated.
This is my code:
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
var refreshToken = HttpContext.Current.Request.Cookies["msal.refreshtoken"];
if (refreshToken != null && !string.IsNullOrEmpty(refreshToken.Value))
{
var newIdToken = TokenService.RefreshIdToken(refreshToken.Value);
var idTokenCookie = new HttpCookie("msal.idtoken", newIdToken)
{
Secure = true,
HttpOnly = true
};
HttpContext.Current.Response.Cookies.Set(idTokenCookie);
return;
}
}
// TokenService.RefreshIdToken
public static string RefreshIdToken(string refreshToken)
{
var policyName = ConfigurationManager.AppSettings["ida:SignUpSignInPolicyId"];
var B2CDomain = ConfigurationManager.AppSettings["ida:B2CDomain"];
var tenant = ConfigurationManager.AppSettings["ida:Tenant"];
var clientId = ConfigurationManager.AppSettings["ida:ClientId"];
var clientSecret = ConfigurationManager.AppSettings["ida:ClientSecret"];
var tokenEndpointUri = $"https://{B2CDomain}/{tenant}/{policyName}/oauth2/v2.0/token";
var httpClient = new HttpClient();
var requestBodyDict = new Dictionary<string, string>
{
{ "grant_type" , "refresh_token" },
{ "client_id" , clientId },
{ "client_secret" , clientSecret },
{ "scope" , $"openid" },
{ "refresh_token" , refreshToken }
};
var request = new HttpRequestMessage
{
RequestUri = new Uri(tokenEndpointUri),
Method = HttpMethod.Post,
Content = new FormUrlEncodedContent(requestBodyDict)
};
var task = Task.Run(() => httpClient.SendAsync(request));
task.Wait();
var response = task.Result;
var task1 = Task.Run(() => response.Content.ReadAsStringAsync());
task1.Wait();
var responseString = task1.Result;
if (response.IsSuccessStatusCode)
{
var idToken = (string)JsonConvert.DeserializeObject<dynamic>(responseString).id_token.ToString();
return idToken;
}
else
{
throw new Exception();
}
}
A couple of thoughts that are too long to put in comments:
Yes the basic idea of ‘use the refresh token to get a new id token’ is how it’s supposed to work.
Googling this question suggests a bewildering array of examples to imitate :-( e.g. Microsoft’s Azure Samples on GitHub for A/D auth for a web app (as opposed to webapi or SPA)
The basic plan for identity problems like this is, find an authoritative example and follow it because that reduces your risk of embarrassing error. ( For instance, Auth0’s example for this scenario says to get a new refresh_token as well as a new id_token. Not doing that might be okay but then the user will be forced to re-login when the refresh token expires. Then you’ll be tempted to use ultra-long-lifetime refresh token, loosening your security a little)
If you can’t find an authoritative example, considering raising an issue or commenting on one.
OTOH, if the code you’ve written works, then maybe you’ve done!
The problem with finding an example to imitate after you’ve got started is trying to find just the right the example for the technology choices you already made. It may be easier to start with an empty project, follow a tutorial, get the tutorial working, then copy the solution back into your app.
To send your user back to their original target you should be able to
var originalUrl= HttpContext.Current.Request.Url;
HttpContext.Current.Response.Redirect(original);
But only do that if getting the id_token succeeded otherwise it creates an infinite loop.
I've the the latest version of Linq to Twitter (3.1.2), and I'm receiving the "Bad Authentication data" error with the code below:
var auth = new ApplicationOnlyAuthorizer
{
CredentialStore = new InMemoryCredentialStore
{
ConsumerKey = "xxxx",
ConsumerSecret = "xxxx"
}
};
using (var twitter = new TwitterContext(auth))
{
var users = twitter.User.Where(s => s.Type == UserType.Search && s.Query == "filter:verified").ToList();
}
I thought at first that it could be Twitter taking a while to accept my new credentials, but I used Twitter's OAuth tool with my keys, and they produced tokens without issue. Any ideas what I'm missing here?
I could not find a duplicate, as the code referenced # https://stackoverflow.com/questions/16387037/twitter-api-application-only-authentication-with-linq2twitter#= is no longer valid in the version I am running.
That query doesn't support Application-Only authorization. Here's the Twitter docs to that:
https://dev.twitter.com/rest/reference/get/users/search
Instead, you can use SingleUserAuthorizer, documented here:
https://github.com/JoeMayo/LinqToTwitter/wiki/Single-User-Authorization
Like this:
var auth = new SingleUserAuthorizer
{
CredentialStore = new SingleUserInMemoryCredentialStore
{
ConsumerKey = ConfigurationManager.AppSettings["consumerKey"],
ConsumerSecret = ConfigurationManager.AppSettings["consumerSecret"],
AccessToken = ConfigurationManager.AppSettings["accessToken"],
AccessTokenSecret = ConfigurationManager.AppSettings["accessTokenSecret"]
}
};
To find out what type of authorization is possible, you can visit the L2T wiki at:
https://github.com/JoeMayo/LinqToTwitter/wiki
and each API query and command has a link at the bottom of the page to the corresponding Twitter API documentation.
As the title suggests, my goal here is to be able to send a tweet from a script.gs. The tweet would be posted to my feed, ideally without me having to visit the Twitter website.
I wrote two main functions to attempt this:
script.gs
//post tweet
function oAuth() {
var CONSUMER_KEY = "**********************";
var CONSUMER_SECRET = "*************************************************";
ScriptProperties.setProperty("TWITTER_CONSUMER_KEY", CONSUMER_KEY);
ScriptProperties.setProperty("TWITTER_CONSUMER_SECRET", CONSUMER_SECRET);
var oauthConfig = UrlFetchApp.addOAuthService("twitter");
oauthConfig.setAccessTokenUrl("https://api.twitter.com/oauth/access_token");
oauthConfig.setRequestTokenUrl("https://api.twitter.com/oauth/request_token");
oauthConfig.setAuthorizationUrl("https://api.twitter.com/oauth/authorize");
oauthConfig.setConsumerKey(ScriptProperties.getProperty("TWITTER_CONSUMER_KEY"));
oauthConfig.setConsumerSecret(ScriptProperties.getProperty("TWITTER_CONSUMER_SECRET"));
var options = {muteHttpExceptions: true,oAuthServiceName:'twitter',oAuthUseToken:'always'}
var url = "https://api.twitter.com/1.1/statuses/user_timeline.json";
var response = UrlFetchApp.fetch(url, options).getContentText();
Logger.log(response);
}
function postTweet() {
oAuth();
Logger.log('oAuth complete');
var status = "Tweet";
var Roptions = {
method: "post",
oAuthServiceName: "twitter",
oAuthUseToken: "always",
status: status
};
var url = "https://api.twitter.com/1.1/statuses/update.json";
Logger.log('begin post');
var request = UrlFetchApp.fetch(url, Roptions); //the trouble line. Execution stops.
Logger.log('post complete');
}
After about a day of relentless hacking, I was able to get the first function, oAuth() to work. That logs, well, my user data. However, for the life of me, I cannot figure out what is holding up request. I do get this error: Request failed for returned code 403. Truncated server response: {"errors":[{"message":"SSL is required","code":92}]}. Googling this didn't turn up much. I'm guessing that the issue is somewhere in Roptions. Any help would be appreciated, and I can try to provide further clarification if needed.
Eureka! Here's the solution. The irony is that I had had something like this before, but had dismissed it. Turns out https was my biggest problem. I'll feast on humble pie tonight.
script to send tweet
//post tweet
function oAuth() {
var CONSUMER_KEY = "*************************";
var CONSUMER_SECRET = "**************************************************";
ScriptProperties.setProperty("TWITTER_CONSUMER_KEY", CONSUMER_KEY);
ScriptProperties.setProperty("TWITTER_CONSUMER_SECRET", CONSUMER_SECRET);
var oauthConfig = UrlFetchApp.addOAuthService("twitter");
oauthConfig.setAccessTokenUrl("https://api.twitter.com/oauth/access_token");
oauthConfig.setRequestTokenUrl("https://api.twitter.com/oauth/request_token");
oauthConfig.setAuthorizationUrl("https://api.twitter.com/oauth/authenticate");
oauthConfig.setConsumerKey(ScriptProperties.getProperty("TWITTER_CONSUMER_KEY"));
oauthConfig.setConsumerSecret(ScriptProperties.getProperty("TWITTER_CONSUMER_SECRET"));
var options = {muteHttpExceptions: true,oAuthServiceName:'twitter',oAuthUseToken:'always'}
var url = "https://api.twitter.com/1.1/statuses/user_timeline.json";
var response = UrlFetchApp.fetch(url, options).getContentText();
Logger.log(response);
}
function postTweet() {
oAuth();
Logger.log('oAuth complete');
var status='Test tweet';
var options = {
"method": "post",
"oAuthServiceName": "twitter",
"oAuthUseToken": "always",
"payload":{"status":status}
};
var url = "https://api.twitter.com/1.1/statuses/update.json";
Logger.log('begin post');
var request = UrlFetchApp.fetch(url, options);
Logger.log('post complete');
}
When you register your Twitter app, you have to check the option Allow this application to be used to Sign in with Twitter. This prevents continual Authorize popups. Also, the tweet text CANNOT contain single quotes (').
#J148, oauthConfig depricated and you can't use it anymore;
Now for twitter you have to use OAuth1 for Apps Script. Migration docs:
https://developers.google.com/apps-script/migration/oauth-config?utm_campaign=oauth-appsscript-315&utm_source=gadbc&utm_medium=blog
Sample:
https://github.com/googlesamples/apps-script-oauth1/blob/master/samples/Twitter.gs
To make sample working you have to:
Add "OAuth1 for Apps Script library" to your script project
Declare some stub "Callback URL" in the twitter app's settings
i get an "Incorrect signature" error by Twitter Api while im posting an update to my twitter account from my app.
I use the javascript OAuth library oauth.js.
Here is my code:
consumer.Name =
{ consumerKey : "xxxxxxxdwcececwscwdc",
consumerSecret: "xxrtbujztvfdtcehz5tjv6uvjxbzuku7ik",
serviceProvider:{
signatureMethod : "HMAC-SHA1"
, requestTokenURL : "https://api.twitter.com/oauth/request_token"
, userAuthorizationURL: "https://api.twitter.com/oauth/authorize"
, accessTokenURL : "https://api.twitter.com/oauth/access_token"
, echoURL : "myApp.html"
}
}
function postTweet(consumerName, twitterText){
var accessor = consumer[consumerName];
message = {method: "POST",action: "http://api.twitter.com/1/statuses/update.json",
parameters:{
oauth_token: my_oauth_token// <-- here is the current oauth_token
status: twitterText,
}
}; // end of message
OAuth.completeRequest(message,
{
consumerKey : accessor.consumerKey,
consumerSecret : accessor.consumerSecret
}
);
var authorizationHeader = OAuth.getAuthorizationHeader("", message.parameters);
var requestBody = OAuth.formEncode(message.parameters);
var postTweetText = newXMLHttpRequest();
postTweetText.onreadystatechange = function receiveAccessToken(){
if (postTweetText.readyState == 4) {
blabla
}
netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
postTweetText.open(message.method, message.action, true);
postTweetText.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
postTweetText.setRequestHeader("Authorization", authorizationHeader);//;
postTweetText.send(requestBody);//requestBody
}
}
What am i doing wrong?
}
coming in rather late on this question but hopefully this leads someone with similar issues to a solution.
I had the same response, but it was because I had set up OAuth with a different app, had saved those credentials and then tried posting to a different registered app on Twitter. Hence, an incorrect signature because I was trying to authenticate with a different app's credentials.
Fixed by nuking the binary and doing a clean/build.
I've been able setup the oAuth calls to get the users access Token following a couple blog posts:
http://sudheerkovalam.wordpress.com/2010/08/28/a-windows-phone-7-twitter-application-part-1/
and
:/byatool.com/c/connect-your-web-app-to-twitter-using-hammock-csharp/comment-page-1/#comment-9955
But I'm having problems sending a status update. I can't find any examples so I may not be setting the proper values. Here's the code which keeps returning: "Could not authenticate with OAuth."
private void Tweet()
{
var credentials = new OAuthCredentials
{
Type = OAuthType.ProtectedResource,
SignatureMethod = OAuthSignatureMethod.HmacSha1,
ParameterHandling = OAuthParameterHandling.HttpAuthorizationHeader,
ConsumerKey = TwitterSettings.ConsumerKey,
ConsumerSecret = TwitterSettings.ConsumerKeySecret,
Token = _settings.AccessToken,
TokenSecret = _settings.AccessTokenSecret,
Version = TwitterSettings.OAuthVersion,
};
var client = new RestClient
{
Authority = "http://twitter.com/oauth",
Credentials = credentials,
HasElevatedPermissions = true
};
var request = new RestRequest
{
Path = "/statuses/update.json",
Method = WebMethod.Post
};
request.AddParameter("status", TwitterTextBox.Text);
client.BeginRequest(request, new RestCallback(TwitterPostCompleted));
}
private void TwitterPostCompleted(RestRequest request, RestResponse response, object userstate)
{
Dispatcher.BeginInvoke(() => MessageBox.Show(response.Content));
}
thanks for any help,
Sam
Ah figured it out finally I was using the wrong URL need to use:
Authority = "http://api.twitter.com" and not: "http://twitter.com/oauth"
Just in case other people find this I've written a blog post on using OAth with Hammock for Twitter. Might be of use to some people!