locked
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/1035


    Matt 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 PM
    Moderator
  • 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