2

I am using TweetSharp to send tweets to users (currently testing it) however it keeps coming back with Bad Authentication Data

{"errors":[{"code":215,"message":"Bad Authentication data."}]}

I have checked my app settings and it has full read and write access. I have also tried to regenerate my consumer keys but still not luck.

here is my code

public ActionResult AccessToken()
{

     string oauth_consumer_key = "<consumer key>";
     string oauth_consumer_secret = "<consumer secret>";

     var service = new TwitterService(oauth_consumer_key, oauth_consumer_secret);

     // Now we need the Token and TokenSecret
     OAuthRequestToken requestToken = service.GetRequestToken("http://localhost:37808/");
     string authURL = service.GetAuthorizationUri(requestToken).ToString();

     Process.Start(authURL);

     SendTweetOptions options = new SendTweetOptions();
     options.Status = "Hello there Twitter";

     service.SendTweet(options);

     var re = service.Response.Response;

     return View();            
    }

Am I doing anything wrong?

KJSR
  • 1,679
  • 6
  • 28
  • 51

3 Answers3

3

Finally solved the issue and it works well. Based upon comments from Yort.

public ActionResult AccessToken()
{
        // Step 1 - Retrieve an OAuth Request Token
        TwitterService service = new TwitterService(ConfigurationManager.AppSettings["TwitterConsumerKey"], ConfigurationManager.AppSettings["TwitterConsumerSecret"]);

        // This is the registered callback URL
        OAuthRequestToken requestToken = service.GetRequestToken("http://localhost:37808/Twitter/OToken");

        // Step 2 - Redirect to the OAuth Authorization URL
        Uri uri = service.GetAuthorizationUri(requestToken);
        return new RedirectResult(uri.ToString(), false /*permanent*/);
        //return View();
}

public ActionResult OToken()
{
        return View();
}

public ActionResult UserInfo(string oauth_token, string oauth_verifier)
{

        var requestToken = new OAuthRequestToken { Token = oauth_token };

        // Step 3 - Exchange the Request Token for an Access Token
        TwitterService service = new TwitterService(ConfigurationManager.AppSettings["TwitterConsumerKey"], 
                                                    ConfigurationManager.AppSettings["TwitterConsumerSecret"]);
        OAuthAccessToken accessToken = service.GetAccessToken(requestToken, oauth_verifier);

        // Step 4 - User authenticates using the Access Token
        service.AuthenticateWith(accessToken.Token, accessToken.TokenSecret);
        TwitterUser user = service.VerifyCredentials(new VerifyCredentialsOptions());
        ViewBag.Message = string.Format("{0}", user.ScreenName);

        // Step 5 - Send Tweet to User TimeLine
        SendTweetOptions options = new SendTweetOptions();

        string URL = "file:\\C:\\Users\\<User>\\Desktop\\test.jpg";
        string path = new Uri(URL).LocalPath;        

        // Sending with Media
        using (var stream = new FileStream(path, FileMode.Open))
        {
            service.SendTweetWithMedia(new SendTweetWithMediaOptions
            {
                Status = "<status>",
                Images = new Dictionary<string, Stream> { { path, stream } }
            });
        }

        var responseText = service.Response.StatusCode;

        if (responseText.ToString() == "OK")
        {
            ViewBag.Message = "Tweet Successful";
        }
        else
        {
            ViewBag.Message = "Tweet Unsuccessful";
        }            
        return View();
    }                                      
}
KJSR
  • 1,679
  • 6
  • 28
  • 51
1

I don't believe you can send Tweets as just a consumer, the Tweets have to be "owned" by a user account. You need to register a Twitter account, then do the full oauth authentication process to get an access token (in addition to the consumer token), then reauthorise the TweetSharp service using both tokens.

Your code above nearly gets there (I think). After the Process.start call there needs to be logic to use the verifier returned in the browser (a number displayed after the user logs in) to complete the auth process and act as that user. At the moment, your code gets half way through that process but does not complete it, so when you try to tweet your TweetSharp service is only authed as the app and not the user.

The originalTweetSharp readme.md does include the missing bits of code. Step 3 needs the actual verifier returned in the browser after login:

// Step 3 - Exchange the Request Token for an Access Token

string verifier = "123456"; // <-- This is input into your application by your user

OAuthAccessToken access = service.GetAccessToken(requestToken, verifier);

// Step 4 - User authenticates using the Access Token service.AuthenticateWith(access.Token, access.TokenSecret);

//Now your tweet call should work here.

It also looks like you're doing this in a web app on the server? In which case you're using entirely the wrong oauth flow (I believe). This one is designed for desktop apps, hence the call that starts a new browser process for the user to login with. I'm not entirely sure how the web flow works as I've never used it, but I believe you need to redirect the user to the authorisation url you receive, and the callback registered with Twitter should point back to your site. I think there is some kind of state parameter that can be passed back through the oauth flow so you can implement your own logic to pickup where you left off based on a session id or similar.

Yort
  • 787
  • 8
  • 22
  • Thank you @Yort for your detailed answer. I believe TweetSharp may not the best way to implement my requirement. I tried the oAuth technique however failed at getting a requestToken, even after many attempts. It seems I shall go back to my original solution and be at it. Thank you – KJSR Sep 04 '16 at 23:57
  • You obviously don't have to use tweetsharp (and probably shouldn't as its no longer supported), but the issue here is understanding and implementing oauth on the client. As far as I know, Twitter only supports oauth1.0a auth now, so you're going to have to figure this out with whichever library you choose. I guess the docs might be better for other libraries, but the basic auth flows remain the same. Maybe try reading the Twitter with docs at dev.twitter.com or the oauth1.0 docs. Good luck! – Yort Sep 06 '16 at 03:19
  • 2
    I got it working using TweetSharp and it very well supports web application. Will post my solution. – KJSR Sep 06 '16 at 16:21
0

I worked on this subject before. You have to developer account before the send tweet because you need tokens and keys. It's my windows service project. I wrote my tokens and key codes in App.config

 <appSettings>
<add key="twitterAccessToken" value="*****"/>
<add key="twitterAccessTokenSecret" value="*****"/>
<add key="twitterConsumerKey" value="*****"/>
<add key="twitterConsumerSecret" value="*****"/>

  public static void SendTweet()
    {
        try
        {
            GetPixelImageFile();

            string key = ConfigurationSettings.AppSettings.Get("twitterConsumerKey");
            string secret = ConfigurationSettings.AppSettings.Get("twitterConsumerSecret");
            string token = ConfigurationSettings.AppSettings.Get("twitterAccessToken");
            string tokenSecret = ConfigurationSettings.AppSettings.Get("twitterAccessTokenSecret");

            string message = "Color, Colorful, Pixel, Art, PixelColouring, Follow";

            var service = new TweetSharp.TwitterService(key, secret);
            service.AuthenticateWith(token, tokenSecret);
            using (var stream = new FileStream(@"C:\Images\Pixel.png", FileMode.Open))
            {
                var result = service.SendTweetWithMedia(new SendTweetWithMediaOptions
                {
                    Status = message,
                    Images = new Dictionary<string, Stream> { { "john", stream } }
                });
                SendMail("SendTweet", (result == null ? "" : result.Text));
            }
        }
        catch (Exception ex)
        {
            SendMail("SendTweet", ex.Message);
        }

    }