3

I have searched for a few days now, high and low and have not been able to get a POST to the twitter API to work correctly. I am able to successfully GET the request token and exchange it for an access token, but when I do a POST to statuses/update, I get a 401 error.

I have verified that the Authorization part of the header is an exact match to what I receive when using Twitter OAuth Tool.

I believe my problem to be the way I am adding the status to the web request's body. Does the url need to be just https://api.twitter.com/1/statuses/update.json, or should it be https://api.twitter.com/1/statuses/update.json?status=MyTweetHere?

My code is as follows:

        public string UpdateStatus(string requestMethod, string baseUrl, string consumerKey, string consumerSecret, string accessToken, OAuthRequestType requestType, string status)
    {
        //baseUrl = https://api.twitter.com/1/statuses/update.json
        const string signatureMethod = "HMAC-SHA1";
        const string oauthVersion = "1.0";

        var timeSpan = (DateTime.UtcNow - new DateTime(1970, 1, 1));
        var timestamp =  (int)timeSpan.TotalSeconds;

        var nonce = CreateNOnce(timestamp, consumerKey, baseUrl, accessToken);
        var signature = CreateSignature(requestMethod, baseUrl, consumerKey, consumerSecret, nonce, signatureMethod, timestamp, accessToken, oauthVersion, string.Empty, string.Empty, requestType, status);

        var bodyData = "status=" + UrlEncode(status);

        var webRequest = (HttpWebRequest)WebRequest.Create(baseUrl);
        webRequest.KeepAlive = true;
        webRequest.ServicePoint.Expect100Continue = false;
        webRequest.Method = requestMethod; //Send in as POST
        webRequest.Accept = "*/*";
        webRequest.UserAgent = "Renicorp.Social";

        webRequest.Headers["Authorization"] = "OAuth " + UrlEncode("oauth_consumer_key") + "=\"" + UrlEncode(consumerKey) + "\", " +
                                                         UrlEncode("oauth_nonce") + "=\"" + UrlEncode(nonce) + "\", " +
                                                         UrlEncode("oauth_signature") + "=\"" + UrlEncode(signature) + "\", " +
                                                         UrlEncode("oauth_signature_method") + "=\"" + UrlEncode(signatureMethod) + "\", " +
                                                         UrlEncode("oauth_timestamp") + "=\"" + UrlEncode(timestamp.ToString()) + "\", " +
                                                         UrlEncode("oauth_token") + "=\"" + UrlEncode(accessToken) + "\", " +
                                                         UrlEncode("oauth_version") + "=\"" + UrlEncode(oauthVersion) + "\"";

        string postData = bodyData;
        byte[] byteArray = Encoding.UTF8.GetBytes(postData);

        webRequest.ContentType = "application/x-www-form-urlencoded";
        webRequest.ContentLength = byteArray.Length;

        using (Stream dataStream = webRequest.GetRequestStream())
        {
            dataStream.Write(byteArray, 0, byteArray.Length);
        }

        //Make the web call and return the response
        WebResponse response = webRequest.GetResponse();
        var responseBody = string.Empty;
        Stream stream = response.GetResponseStream();
        if (stream != null) responseBody = new StreamReader(stream).ReadToEnd();
        return responseBody;
    }

UPDATE: I have written a method now to do a GET for account/verify_credentials.json and am able to verify account credentials if I use my application account key, but when I try to use a separate account and provide the access token, I get 401.

puddinman13
  • 1,408
  • 4
  • 18
  • 35

1 Answers1

1

So my problem was the secret key when creating the signing key. I had hard coded my secret key from my application in twitter. This is why my headers always matched, but when I ran a test using a linked user account, the request wouldn't go through. Moral of the story is not to hard code the secret key. I was wondering the whole time what the secret key was for. Now I know.

Also, the url to use is just the base url: https://api.twitter.com/1/statuses/update.json. No need to add the url parameters. Finally, when creating the http request body, it simply "status=UrlEncode(tweetToBeMade)".

puddinman13
  • 1,408
  • 4
  • 18
  • 35
  • 1
    Great job! Happy you solved it. This one is a tough one! I am dealing myself with a similar task to connect to the API with a signed request as you had to but am yet to get it successfully connected. It is a damn pain, so, good on you that you made it. I am bumping my head again and again at the damn wall from despair. :D But I'll get it right eventually. I also got a helpful post concerning this topic if anyone is interested: https://gist.github.com/smockle/5537203. The Twitter API specs are long and some would say good, but I believe some parts could be better. I get lost in it sometimes. – AlexRebula Aug 03 '17 at 01:09