I have been working with Linq2Twitter (v. 2), using the Search API and
I wanted to switch to the Stream API. I updated to v. 3 but since then I don't manage to authenticate anymore. I don't think the Stream API or the version could be the problem, because I've tried to go back to the previous version, previous authentication methods, and it doesn't work anymore either. I get a 401 : bad authentication data.
So, here is my current code :
var auth = new SingleUserAuthorizer
{
CredentialStore = new SingleUserInMemoryCredentialStore()
{
ConsumerKey = ConfigurationManager.AppSettings["twitterConsumerKey"],
ConsumerSecret = ConfigurationManager.AppSettings["twitterConsumerSecret"],
OAuthToken = ConfigurationManager.AppSettings["twitterOAuthToken"],
AccessToken = ConfigurationManager.AppSettings["twitterAccessToken"]
}
};
TwitterContext _twitterCtx = new TwitterContext(auth);
try
{
var verifyResponse =
await
(from acct in _twitterCtx.Account
where acct.Type == AccountType.VerifyCredentials
select acct)
.SingleOrDefaultAsync();
if (verifyResponse != null && verifyResponse.User != null)
{
User user = verifyResponse.User;
Console.WriteLine(
"Credentials are good for {0}.",
user.ScreenNameResponse);
}
}
catch (TwitterQueryException tqe)
{
Console.WriteLine(tqe.Message);
}
Of course, I checked the credentials several times, printed them out and all.
I tried with ApplicationOnlyAuthorizer, v.2, v.3 as well, it doesn't change anything.
What scares me the most is that what used to work (v2 + ApplicationOnly + Search API) doesn't work either.
Through my research I've heard of a problem caused by unsynchronized timestamps, or something like that. But I don't understand how I can change that.
The program is not on a server, it's locally stored.
Thank you for reading.
Here's how to use SingleUserAuthorizer in v3.0:
var auth = new SingleUserAuthorizer
{
CredentialStore = new SingleUserInMemoryCredentialStore
{
ConsumerKey = ConfigurationManager.AppSettings["consumerKey"],
ConsumerSecret = ConfigurationManager.AppSettings["consumerSecret"],
AccessToken = ConfigurationManager.AppSettings["accessToken"],
AccessTokenSecret = ConfigurationManager.AppSettings["accessTokenSecret"]
}
};
Notice here that I'm setting AccessToken and AccessToken secret. I also have a FAQ with suggestions for resolving 401 problems:
https://linqtotwitter.codeplex.com/wikipage?title=LINQ%20to%20Twitter%20FAQ&referringTitle=Documentation
Related
Im newbie in C#, I have been asked to implement the OpenID login with provided username and password and get the bearer token.
We achieved this in Java code snipped is as below.(don't know how do same in C#)
public AccessTokenResponse getToken() throws IOException, ParseException, Exception {
StringBuilder query = new StringBuilder("");
ClientCredentialsGrant clientAuth = new ClientCredentialsGrant();
Map<String, String> parameters = clientAuth.toParameters();
for (String key : parameters.keySet()) {
query.append(key).append("=").append(parameters.get(key)).append("&");
}
ClientID clientID = new ClientID(config.getProperty(ConfigConstants.USERNAME));
Secret secret = new Secret(config.getPassword());
ClientSecretBasic csb = new ClientSecretBasic(clientID, secret);
//logger.info("URL:" + this.getOpenIDMetadata(config.getProperty(ConfigConstants.DOMAIN)).getTokenEndpointURI().toString());
TokenRequest tokenRequest = new TokenRequest(this.getOpenIDMetadata(config.getProperty(ConfigConstants.DOMAIN)).getTokenEndpointURI(), csb, clientAuth);
HTTPRequest request = tokenRequest.toHTTPRequest();
HTTPResponse httpResponse = request.send();
accessToken = AccessTokenResponse.parse(httpResponse);
return accessToken;
}
We have a server which is an openid provider and this is how get the OIDCProviderMetadata
private OIDCProviderMetadata getOpenIDMetadata(String domain) throws Exception {
if (this.metadata == null) {
String confURL = this.serverURL+ config.getIDP() + domain + "/authn/.well-known/openid-configuration";
HTTPRequest configRequest = new HTTPRequest(HTTPRequest.Method.GET, new URL(confURL));
HTTPResponse configResponse = configRequest.send();
metadata = OIDCProviderMetadata.parse(configResponse.getContent());
}
return metadata;
}
Question is how to implement same thing in C#?
I did some research around this, found there is/are official OpendID implementation in C# i.e.
https://github.com/IdentityModel/IdentityModel.OidcClient2
but did not find any samples which will help me to implement likewise in Java implementation i have. All examples demonstrate do openid login in browser or mobiles devices i don't want that, I want similar implementation as we have in Java(above).
Any help would be appreciated or code snipped would be more helpful.
Every Example I can find is either very outdated or always comes back 401.
Can anyone at all provide a working example of posting a status update to twitter?
Even the below always fails.
I get redirected to twitter - great. I can confrim the access codes are correct and match my application, but on acutally posting the update - error is unknown...
What on earth is wrong here? Does matter what app I use or which twitter account.
Using Twitteriser2.dll
if (Request["oauth_token"] == null)
{
OAuthTokenResponse reqToken = OAuthUtility.GetRequestToken(
oauth_consumer_key,
oauth_consumer_secret,
Request.Url.AbsoluteUri);
Response.Redirect(string.Format("http://twitter.com/oauth/authorize?oauth_token={0}",
reqToken.Token));
}
else
{
string requestToken = Request["oauth_token"].ToString();
string pin = Request["oauth_verifier"].ToString();
var tokens = OAuthUtility.GetAccessToken(
oauth_consumer_key,
oauth_consumer_secret,
requestToken,
pin);
OAuthTokens accesstoken = new OAuthTokens()
{
AccessToken = tokens.Token,
AccessTokenSecret = tokens.TokenSecret,
ConsumerKey = oauth_consumer_key,
ConsumerSecret = oauth_consumer_secret
};
TwitterResponse<TwitterStatus> response = TwitterStatus.Update(
accesstoken,
"Testing!! It works (hopefully).");
if (response.Result == RequestResult.Success)
{
Response.Write("we did it!");
}
else
{
Response.Write("it's all bad.");
}
}
The TwitterRepsonse object has an "ErrorMessage" property. You should probably start by looking at the information in there to give you some guidance.
Why don't you use Tweetinvi. Tweetinvi will allow you to post in 1 line and get error messages in line too. Here is an example.
TwitterCredentials.SetCredentials("Access_Token", "Access_Token_Secret", "Consumer_Key", "Consumer_Secret");
var tweet = Tweet.PublishTweet("Hello!");
if (tweet == null)
{
var exceptionDetails = ExceptionHandler.GetLastException().TwitterExceptionInfos.First().Message;
}
You can find the documentation here : https://tweetinvi.codeplex.com/documentation
Also have a look at https://tweetinvi.codeplex.com/discussions/536895 if you are using it with ASP.NET.
Got it working eventually.
The fault isn't exactly known as I didn't have to change the code but what I did was re-download Twitterizwer and Built it (Required adding a ref to C++ components for what ever reason) and it then worked so I can only see that it was somehow faulty the first time round.
Having read that since late last year LinkedIn finally have finally allowed us to retrieve the email address for the currently logged on user I've been failing to do so. I've read all the posts I can find on SO and elsewhere and as far as I can tell my code should be working. It returns just fine with all the other fields,
however, the email address field is always empty.
Here's my LinkedInClient class;
public class LinkedInClient2 : OAuthClient
{
public static readonly ServiceProviderDescription LinkedInServiceDescription = new ServiceProviderDescription
{
AccessTokenEndpoint =
new MessageReceivingEndpoint(
"https://api.linkedin.com/uas/oauth/accessToken",
HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest),
RequestTokenEndpoint =
new MessageReceivingEndpoint(
"https://api.linkedin.com/uas/oauth/requestToken?scope=r_basicprofile+r_emailaddress",
HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest),
UserAuthorizationEndpoint =
new MessageReceivingEndpoint(
"https://www.linkedin.com/uas/oauth/authenticate",
HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest),
TamperProtectionElements = new ITamperProtectionChannelBindingElement[] { new HmacSha1SigningBindingElement() },
ProtocolVersion = ProtocolVersion.V10a
};
public LinkedInClient2(string consumerKey, string consumerSecret, IConsumerTokenManager tokenManager)
: base("linkedIn", LinkedInServiceDescription, tokenManager)
{
}
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "We don't care if the request fails.")]
protected override AuthenticationResult VerifyAuthenticationCore(AuthorizedTokenResponse response)
{
// See here for Field Selectors API http://developer.linkedin.com/docs/DOC-1014
const string ProfileRequestUrl = "https://api.linkedin.com/v1/people/~:(id,first-name,last-name,email-address,headline,industry,summary,picture-url)";
string accessToken = response.AccessToken;
var profileEndpoint = new MessageReceivingEndpoint(ProfileRequestUrl, HttpDeliveryMethods.GetRequest);
HttpWebRequest request = this.WebWorker.PrepareAuthorizedRequest(profileEndpoint, accessToken);
try
{
using (WebResponse profileResponse = request.GetResponse())
{
using (Stream responseStream = profileResponse.GetResponseStream())
{
XDocument document = LoadXDocumentFromStream(responseStream);
string userId = document.Root.Element("id").Value;
// User Profile Fields - https://developer.linkedin.com/documents/profile-fields
string firstName = document.Root.Element("first-name").Value;
string lastName = document.Root.Element("last-name").Value;
string userName = document.Root.Element("email-address").Value; // <<<<<< ERROR - always empty
var extraData = new Dictionary<string, string>();
extraData.Add("accesstoken", accessToken);
extraData.Add("name", userName);
extraData.AddDataIfNotEmpty(document, "picture-url");
extraData.AddDataIfNotEmpty(document, "location");
extraData.AddDataIfNotEmpty(document, "headline");
extraData.AddDataIfNotEmpty(document, "summary");
extraData.AddDataIfNotEmpty(document, "industry");
return new AuthenticationResult(
isSuccessful: true, provider: this.ProviderName, providerUserId: userId, userName: userName, extraData: extraData);
}
}
}
catch (Exception exception)
{
return new AuthenticationResult(exception);
}
}
internal static XDocument LoadXDocumentFromStream(Stream stream)
{
const int MaxChars = 0x10000; // 64k
XmlReaderSettings settings = new XmlReaderSettings()
{
MaxCharactersInDocument = MaxChars
};
return XDocument.Load(XmlReader.Create(stream, settings));
}
}
}
I realise that I'm supposed to add the scope=r_emailaddress to the RequestTokenEndpoint (which I have) but from the fiddler traces I can't even see that endpoint being fetched. Basically, it only every uses the AccessTokenEndpoint which presumably is something to do with my problem.
This is approximately how my ASP.Net MVC4.5 controller looks;
[AllowAnonymous]
public virtual ActionResult LinkedIn(string returnUrl)
{
var tokenMgr = new RepoOAuthTokenManager(_iOtk, LinkedInAppKey, LinkedInAppSecret);
var iacp = new LinkedInClient2(LinkedInAppKey, LinkedInAppSecret, tokenMgr); // if none specified, LinkedInClient uses the AuthenticationOnlyCookieOAuthTokenManager which doesn't work for APIs
var ioadp = new MyOauthDataProvider();
var oasm = new OpenAuthSecurityManager(this.HttpContext, iacp, ioadp);
var redirectUri = Url.ActionFullyQualified(this.nameof(c => c.LinkedIn(null)), null, new RouteValueDictionary(new { returnUrl = returnUrl }));
AuthenticationResult ar = oasm.VerifyAuthentication(redirectUri);
if (ar.Error == null)
{
if (ar.IsSuccessful)
DoSomethingResultingInRedirect(redirectUri); // OK
else
oasm.RequestAuthentication(redirectUri);
}
else
ModelState.AddModelError("", ar.Error.Message);
return View(this.nameof(c=>c.Login(null)));
}//LinkedIn
I can't say I completely understand the extensibility mechanism in DotNetOpenAuth and I may be misunderstanding something so I'd appreciate some pointers.
Am I missing a step somewhere?
I have two solutions to this, although I still don't understand how to get my existing code to work as I'd expect, but hopefully this may help someone else;
(1) I went to Making it easier for you to add default member permissions and clicked on the API admin page.
Here you can select what scopes you want requested by default. It didn't work until I clicked a box (now disappeared) that was worded along the lines of "[x] Make this permanent". Once I'd done that I started to get the email-address field populated as I was expecting.
(2) I tried using the OAuth2 URL instead from information here and it seemed to work. I have also found an implementation of an OAuth2 client here which looks like a good start. I suspect that in the long run, an OAuth2 upgrade (once the spec is more static) will yield better overall mileage.
For now though, I'm out of the pit of despair, but other answers are still welcome!
I had a similar issue.. maybe this is relevant for you:
My Request Token Call is:
https://api.linkedin.com/v1/people/~:(id,first-name,last-name,headline,member-url-resources,picture-url,location,public-profile-url,email-address)?format=json
but the json response is:
array(8) {
["emailAddress"]=>
string(18) "email#email.com"
["firstName"]=>
string(3) "Tim"
...
Note that in the first case email is named email-address, in the second emailAddress.
So I've looked at all the of the suggestions from the Linq to Twitter documentation regarding 401 statuses with Oauth and I honestly don't know what I'm doing wrong.
var auth = new PinAuthorizer
{
Credentials = new InMemoryCredentials
{
ConsumerKey = ConfigurationManager.AppSettings["twitterConsumerKey"],
ConsumerSecret = ConfigurationManager.AppSettings["twitterConsumerSecret"],
//OAuthToken = ConfigurationManager.AppSettings["twitterOAuthToken"], //don't include this
//AccessToken = ConfigurationManager.AppSettings["twitterAccessToken"] //or this for new users.
},
//
UseCompression = true,
GoToTwitterAuthorization = pageLink => Process.Start(pageLink),
GetPin = () =>
{
Console.WriteLine("/nAfter twitter authorizes your application you will be returned here or something/n");
Console.Write("Enter Pin here:");
return Console.ReadLine();
}
};
auth.Authorize();
using (var twitterCtx = new TwitterContext(auth, "https://api.twitter.com/1/",
"https://search.twitter.com/"))
{
try
{
twitterCtx.Log = Console.Out;
Console.WriteLine("Please provide tweet text");
string tweet = Console.ReadLine();
twitterCtx.UpdateStatus(tweet);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
I've ran this using the Pin Authentication method as well as the single user method (providing the oauth keys with config file). I'm able to query tweets but I can't update my status or send direct messages (I receive a 403 forbidden when I try to DM). I've provided a callback URL (albeit fake) so I can't think of why this isn't working. Any help would be appreciated.
PS this runs in Main, not sure if that matters
All you need is this overload of the TwitterContext ctor and it will use the proper base URLs:
new TwitterContext(auth)
The example you're using is for v1.0 URLs and LINQ to Twitter is on Twitter API v1.1 now. It will default to the proper base URLs.
If you're querying okay, but getting errors on update and DM, double check to make sure you aren't trying to tweet the same text. That's why I append a DateTime.Now to the end of test tweets - to guarantee uniqueness.
Coding Platform ASP.NET 4.0 WebForms
I have two pages that are relevant here
Login.aspx
LandingPage.aspx
On Login.aspx when I click an ImageButton, I redirect to Facebook site with the following code
protected void FacebookLoginButton_Click(object sender, ImageClickEventArgs e)
{
try
{
Response.Redirect(GetFacebookLoginURL());
}
catch (System.Threading.ThreadAbortException)
{
throw;
}
catch (Exception err)
{
Elmah.ErrorSignal.FromCurrentContext().Raise(err);
}
}
private string GetFacebookLoginURL()
{
try
{
string baseURL = System.Configuration
.ConfigurationManager
.AppSettings["WebsiteURL"]
.ToString();
string[] extendedPermissions = new[] {
"publish_stream",
"offline_access"
};
var oauth = new FacebookOAuthClient {
ClientId = FacebookContext.Current.AppId
};
var parameters = new Dictionary<string, object>{
{ "response_type", "token" },
{ "display", "page" }
};
if (extendedPermissions != null && extendedPermissions.Length > 0)
{
var scope = new StringBuilder();
scope.Append(string.Join(",", extendedPermissions));
parameters["scope"] = scope.ToString();
}
parameters["redirect_uri"] = String.Format("{0}LandingPage.aspx", baseURL);
return oauth.GetLoginUrl(parameters).OriginalString;
}
catch (Exception err)
{
Elmah.ErrorSignal.FromCurrentContext().Raise(err);
return "";
}
}
That part is working properly. But I am clueless on how to access the user info at the LandingPage which is my redirect_uri. Have tried this.
FacebookOAuthClient cl = new FacebookOAuthClient(FacebookContext.Current);
FacebookOAuthResult result = null;
string url = Request.Url.AbsoluteUri;
// verify that there is a code in the url
if (FacebookOAuthResult.TryParse(url, out result))
{
if (result.IsSuccess)
{
var accesstoken = result.AccessToken;
}
else
{
var errorDescription = result.ErrorDescription;
var errorReason = result.ErrorReason;
}
}
But I doubt it wont work since I dont have window.hash.location at Server Side(Its not working anyway)
var client = new FacebookClient(FacebookContext.Current);
dynamic me = client.Get("me");
string firstName = me.first_name;
string lastName = me.last_name;
string email = me.email;
Although I am not sure, getting the Access Token will solve my problem, won't it?
This is the error I am getting.
(OAuthException) An active access
token must be used to query
information about the current user.
What am I doing wrong?
here's a sample of a standalone website using webforms. Check out Default.aspx.cs and Web.config. Please note that this sample could be modified for use with the latest source code and might not work with the latest release (5.0.3 beta).
I just recently did this implementation. To access "me", you need to have an Access Token.
The implementation is pretty straighforward, however, I will say that I found the major stumbling block for me was to make sure that my redirect_uri from my "Login.aspx" url matched the redirect_uri from my landing page.
It must be simple, but I dodnt get it. So I used the lesser used Facebook C# SDK by Facebook. I pretty much did what this blog suggested. Everything is fine now.