Asked by:
401 Unauthorized (WebException) while posting status on Twitter from Universal app

Question
-
I want to give a feature to login to Twitter & to post Tweet from Windows 8.1 Universal app. Please don't suggest me to go for 3rd party library. I just want to do two things only. My efforts are given below. I doubt my authentication is wrong. I am getting System.Net.WebException => The remote server returned an error: (401) Unauthorized. What's wrong with my code, any one has idea?
public const string TwitterClientID = "XXXXXXXXXXXL3nZGhtKURASXg"; public const string TwitterClientSecret = "5HBuM1FVXXXXXXXXXXXXXXqaSm1awtNSes"; public const string TwitterCallbackUrl = "http://f.com"; public const string TweetFromAPI = "Tweeting from API"; String Oauth_token = null; String Oauth_token_secret = null; private async Task TwitterLogin() { TimeSpan SinceEpoch = (DateTime.Now - new DateTime(1970, 1, 1, 0, 0, 0, 0).ToLocalTime()); Random Rand = new Random(); String TwitterUrl = "https://api.twitter.com/oauth/request_token"; Int32 Nonce = Rand.Next(1000000000); String SigBaseStringParams = "oauth_callback=" + Uri.EscapeDataString(TwitterCallbackUrl); SigBaseStringParams += "&" + "oauth_consumer_key=" + TwitterClientID; SigBaseStringParams += "&" + "oauth_nonce=" + Nonce.ToString(); SigBaseStringParams += "&" + "oauth_signature_method=HMAC-SHA1"; SigBaseStringParams += "&" + "oauth_timestamp=" + Math.Round(SinceEpoch.TotalSeconds); SigBaseStringParams += "&" + "oauth_version=1.0"; String SigBaseString = "POST&"; SigBaseString += Uri.EscapeDataString(TwitterUrl) + "&" + Uri.EscapeDataString(SigBaseStringParams); IBuffer KeyMaterial = CryptographicBuffer.ConvertStringToBinary(TwitterClientSecret + "&", BinaryStringEncoding.Utf8); MacAlgorithmProvider HmacSha1Provider = MacAlgorithmProvider.OpenAlgorithm("HMAC_SHA1"); CryptographicKey MacKey = HmacSha1Provider.CreateKey(KeyMaterial); IBuffer DataToBeSigned = CryptographicBuffer.ConvertStringToBinary(SigBaseString, BinaryStringEncoding.Utf8); IBuffer SignatureBuffer = CryptographicEngine.Sign(MacKey, DataToBeSigned); String Signature = CryptographicBuffer.EncodeToBase64String(SignatureBuffer); String DataToPost = "OAuth oauth_callback=\"" + Uri.EscapeDataString(TwitterCallbackUrl) + "\", oauth_consumer_key=\"" + TwitterClientID + "\", oauth_nonce=\"" + Nonce.ToString() + "\", oauth_signature_method=\"HMAC-SHA1\", oauth_timestamp=\"" + Math.Round(SinceEpoch.TotalSeconds) + "\", oauth_version=\"1.0\", oauth_signature=\"" + Uri.EscapeDataString(Signature) + "\""; var m_PostResponse = await PostData(TwitterUrl, DataToPost, false); if (m_PostResponse != null) { String[] keyValPairs = m_PostResponse.Split('&'); for (int i = 0; i < keyValPairs.Length; i++) { String[] splits = keyValPairs[i].Split('='); switch (splits[0]) { case "oauth_token": Oauth_token = splits[1]; break; case "oauth_token_secret": Oauth_token_secret = splits[1]; break; } } if (Oauth_token != null) { TwitterUrl = "https://api.twitter.com/oauth/authorize?oauth_token=" + Oauth_token; System.Uri StartUri = new Uri(TwitterUrl); System.Uri EndUri = new Uri(TwitterCallbackUrl); WebAuthenticationResult WebAuthenticationResult = await WebAuthenticationBroker.AuthenticateAsync( WebAuthenticationOptions.None, StartUri, EndUri); if (WebAuthenticationResult.ResponseStatus == WebAuthenticationStatus.Success) { var text = WebAuthenticationResult.ResponseData.Split(new char[] { '?' })[1]; var dict = text.Split(new[] { '&' }, StringSplitOptions.RemoveEmptyEntries) .Select(part => part.Split('=')) .ToDictionary(split => split[0], split => split[1]); //Oauth_token = dict["oauth_token"]; //Oauth_token_secret = dict["oauth_verifier"]; await PostTweet(); } else if (WebAuthenticationResult.ResponseStatus == WebAuthenticationStatus.ErrorHttp) { } else { } } } } private async Task<String> PostData(String Url, String Data, bool flag) { string m_PostResponse = null; try { HttpWebRequest Request = (HttpWebRequest)WebRequest.Create(Url); Request.Method = "POST"; if (flag) { Request.ContentType = "application/x-www-form-urlencoded"; } Request.Headers["Authorization"] = Data; if (flag) { using (Stream stream = await Request.GetRequestStreamAsync()) { var postBody = "status=" + Uri.EscapeDataString(TweetFromAPI); byte[] content = System.Text.Encoding.UTF8.GetBytes(postBody); stream.Write(content, 0, content.Length); } } HttpWebResponse Response = (HttpWebResponse)await Request.GetResponseAsync(); StreamReader ResponseDataStream = new StreamReader(Response.GetResponseStream()); m_PostResponse = await ResponseDataStream.ReadToEndAsync(); } catch (Exception) { throw; } return m_PostResponse; } public async Task PostTweet() { Random Rand = new Random(); Int32 Nonce = Rand.Next(1000000000); string status = TweetFromAPI; string postBody = "status=" + Uri.EscapeDataString(status); string oauth_consumer_key = TwitterClientID; string oauth_consumerSecret = TwitterClientSecret; string oauth_signature_method = "HMAC-SHA1"; string oauth_version = "1.0"; string oauth_token = Oauth_token; string oauth_token_secret = Oauth_token_secret; string oauth_nonce = Nonce.ToString(); TimeSpan timeSpan = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0); string oauth_timestamp = Convert.ToInt64(timeSpan.TotalSeconds).ToString(); SortedDictionary<string, string> basestringParameters = new SortedDictionary<string, string>(); basestringParameters.Add("status", Uri.EscapeDataString(status)); basestringParameters.Add("oauth_version", oauth_version); basestringParameters.Add("oauth_consumer_key", oauth_consumer_key); basestringParameters.Add("oauth_nonce", oauth_nonce); basestringParameters.Add("oauth_signature_method", oauth_signature_method); basestringParameters.Add("oauth_timestamp", oauth_timestamp); basestringParameters.Add("oauth_token", oauth_token); //Build the signature string string baseString = String.Empty; baseString += "POST" + "&"; baseString += Uri.EscapeDataString("https://api.twitter.com/1.1/statuses/update.json") + "&"; foreach (KeyValuePair<string, string> entry in basestringParameters) { baseString += Uri.EscapeDataString(entry.Key + "=" + entry.Value + "&"); } baseString = baseString.Substring(0, baseString.Length - 3); //Build the signing key string signingKey = Uri.EscapeDataString(oauth_consumerSecret) + "&" + Uri.EscapeDataString(oauth_token_secret); IBuffer KeyMaterial = CryptographicBuffer.ConvertStringToBinary(TwitterClientSecret + "&", BinaryStringEncoding.Utf8); MacAlgorithmProvider HmacSha1Provider = MacAlgorithmProvider.OpenAlgorithm("HMAC_SHA1"); CryptographicKey MacKey = HmacSha1Provider.CreateKey(KeyMaterial); IBuffer DataToBeSigned = CryptographicBuffer.ConvertStringToBinary(signingKey, BinaryStringEncoding.Utf8); IBuffer SignatureBuffer = CryptographicEngine.Sign(MacKey, DataToBeSigned); String signatureString = CryptographicBuffer.EncodeToBase64String(SignatureBuffer); string authorizationHeaderParams = String.Empty; authorizationHeaderParams += "OAuth "; authorizationHeaderParams += "oauth_nonce=" + "\"" + Nonce.ToString() + "\","; authorizationHeaderParams += "oauth_signature_method=" + "\"" + Uri.EscapeDataString(oauth_signature_method) + "\","; authorizationHeaderParams += "oauth_timestamp=" + "\"" + Uri.EscapeDataString(oauth_timestamp) + "\","; authorizationHeaderParams += "oauth_consumer_key=" + "\"" + Uri.EscapeDataString(oauth_consumer_key) + "\","; authorizationHeaderParams += "oauth_token=" + "\"" + Uri.EscapeDataString(oauth_token) + "\","; authorizationHeaderParams += "oauth_signature=" + "\"" + Uri.EscapeDataString(signatureString) + "\","; authorizationHeaderParams += "oauth_version=" + "\"" + Uri.EscapeDataString(oauth_version) + "\""; var respo = await PostData("https://api.twitter.com/1.1/statuses/update.json", authorizationHeaderParams, true); }
Tuesday, May 13, 2014 11:27 AM
All replies
-
Are you sure there's not a Twitter problem?
https://dev.twitter.com/issues/1035Matt Small - Microsoft Escalation Engineer - Forum Moderator
If my reply answers your question, please mark this post as answered.
NOTE: If I ask for code, please provide something that I can drop directly into a project and run (including XAML), or an actual application project. I'm trying to help a lot of people, so I don't have time to figure out weird snippets with undefined objects and unknown namespaces.Tuesday, May 13, 2014 7:16 PMModerator -
I am not sure, if there's Twitter problem or not. I urge you to run my code once. If you need real Twitter client ID & secret, I can mail you.Wednesday, May 14, 2014 5:22 AM
-
This is a different kind of solution: why not use the sample from the WebAuthenticationBroker? In that sample, there's an Http "filter" that you can plug into your Windows.Web.Http HttpClient processing pipeline; the filter then handles oauth for you with a minimum of information.
Even better: it means your app code can make really straightforward calls to the twitter API without having to handle all of the signing, callback, retries, UI for logging in, and whatnot.
Link: http://code.msdn.microsoft.com/wpapps/Web-Authentication-d0485122
Network Developer Experience Team (Microsoft)
Wednesday, May 14, 2014 9:31 PM -
Thanks for your answer. I tried the sample to manipulate it to post tweet. but still I am getting unauthorized 401, code & error message is given below. Please help me to rectify my code. I need that code ASAP since I need to meet deadline.
{ "errors": [ { "message": "Invalid or expired token", "code": 89 } ] }
private async Task PostOnTwitter(string webAuthResultResponseData) { string responseData = webAuthResultResponseData.Substring(webAuthResultResponseData.IndexOf("oauth_token")); string request_token = null; string oauth_verifier = null; String[] keyValPairs = responseData.Split('&'); for (int i = 0; i < keyValPairs.Length; i++) { String[] splits = keyValPairs[i].Split('='); switch (splits[0]) { case "oauth_token": request_token = splits[1]; break; case "oauth_verifier": oauth_verifier = splits[1]; break; } } String TwitterUrl = "https://api.twitter.com/1.1/statuses/update.json"; string timeStamp = GetTimeStamp(); string nonce = GetNonce(); String SigBaseStringParams = "oauth_consumer_key=" + TwitterClientID.Text; SigBaseStringParams += "&" + "oauth_nonce=" + nonce; SigBaseStringParams += "&" + "oauth_signature_method=HMAC-SHA1"; SigBaseStringParams += "&" + "oauth_timestamp=" + timeStamp; SigBaseStringParams += "&" + "oauth_token=" + request_token; SigBaseStringParams += "&" + "oauth_version=1.0"; SigBaseStringParams += "&" + "status=" + Uri.EscapeDataString(TweetFromAPI); String SigBaseString = "POST&"; SigBaseString += Uri.EscapeDataString(TwitterUrl) + "&" + Uri.EscapeDataString(SigBaseStringParams); String Signature = GetSignature(SigBaseString, TwitterClientSecret.Text); HttpStringContent httpContent = new HttpStringContent("oauth_verifier=" + oauth_verifier, Windows.Storage.Streams.UnicodeEncoding.Utf8); httpContent.Headers.ContentType = HttpMediaTypeHeaderValue.Parse("application/x-www-form-urlencoded"); string authorizationHeaderParams = "oauth_consumer_key=\"" + TwitterClientID.Text + "\", oauth_nonce=\"" + nonce + "\", oauth_signature_method=\"HMAC-SHA1\", oauth_signature=\"" + Uri.EscapeDataString(Signature) + "\", oauth_timestamp=\"" + timeStamp + "\", oauth_token=\"" + Uri.EscapeDataString(request_token) + "\", oauth_version=\"1.0\""; var contetn = new HttpMultipartContent(); contetn.Add(new HttpStringContent("oauth_verifier=" + oauth_verifier, Windows.Storage.Streams.UnicodeEncoding.Utf8)); var postBody = "status=" + Uri.EscapeDataString(TweetFromAPI); var content = System.Text.Encoding.UTF8.GetBytes(postBody).AsBuffer(); contetn.Add(new HttpBufferContent(content)); HttpClient httpClient = new HttpClient(); httpClient.DefaultRequestHeaders.Authorization = new HttpCredentialsHeaderValue("OAuth", authorizationHeaderParams); var httpResponseMessage = await httpClient.PostAsync(new Uri(TwitterUrl), contetn); string response = await httpResponseMessage.Content.ReadAsStringAsync(); }
- Edited by Xyroid Thursday, May 15, 2014 6:37 AM
Thursday, May 15, 2014 6:25 AM