twitter-ruby: Asterisks not encoded properly and result in error 32 "Could not authenticate you."

Twitter-text (1.11.0) says that tweets with asterisks are valid. And I am also allowed to post them to Twitter directly. However, when posted through the Twitter gem (6.0.0) I receive the error: “Could not authenticate you.” (code 32)

Twitter::Validation.tweet_invalid?("*TEST* Does this work?") # returns false (valid tweet)

client.update("*TEST* Does this work?") # raises Twitter::Error::Unauthorized: Could not authenticate you.

client.update("TEST Does this work?") # works

This forum post indicates that asterisks need to be URL encoded to be valid, so shouldn’t the Twitter gem be handling this for me? https://twittercommunity.com/t/asterisk/6343

About this issue

  • Original URL
  • State: closed
  • Created 9 years ago
  • Comments: 18 (5 by maintainers)

Commits related to this issue

Most upvoted comments

Reviving this one to say it’s still affecting the latest version

I’m an experienced developer, but I don’t speak Ruby. However, I went along with @Gordin in a long Twitter conversation (German though) while he dug into the issue and can confirm his conclusions.

Let me try to summarize what everyone has said:

  • OAuth 1.0a (used by the Twitter API and implemented in this project using laserlemon/simple_oauth) requires the signature of a request to be computed over the request parameters encoded as described in RFC 3986, which states that * is to be replaced by %2A. (Twitter’s API docs are very clear about this, too.)
  • HTTP::FormData (used by this project to do the actual HTTP request) on the other hand encodes according to the rules of Ruby’s encode_www_form, which implements the HTML5 candidate recommendation, and for HTML5, * (0x2a) is not to be escaped anymore.
  • Twitter itself, when verifying the request, seems to compute the signature against the raw HTTP POST request, which will contain an unescaped asterisk produced by HTTP::FormData. But the signature we provide was made over a string containing an escaped asterisk as required by OAuth. Thus, the signature check fails and the tweet is rejected.
    • Twitter could of course adhere to Postel’s Law, decode the incoming request in a more liberal way, and then compute its own signature according to OAuth’s rules by re-escaping the data in the RFC 3986 way, but alas, they don’t.

None of the libraries that this project is using is really at fault here: They all do their job correctly. However, the OAuth and the HTTP code escape the parameters according to different standards, which then causes the issue. That makes this library the correct place to fix it, because it is supposed to connect all the threads correctly, and it doesn’t. (Sorry 😉)

Overriding the way in which the parameters are escaped in the HTTP request seems to be the only way to do this, and apart from switching to a different HTTP library, the snippet suggested by @Gordin seems to me to be the best solution.

For me, the issue is only for asteriks. Other chars gets posted.

If the http-form_data gem would allow you to customize encoding on a per-instance basis and we could pass in an encoder through the http gem this could solve the problem without having to use caller to determine what’s making the request. I’ve opened https://github.com/httprb/form_data/pull/29 to see if that’s a possible direction.

Running into this issue as well.

Does anyone know if it’s just asterisks leading to problems, or other characters as well?

Sorry to re-raise this topic, but I’m getting the same on master. I am going around temporarily by replacing asterisk by *. I also tried what dredenba suggested of using the url encoded version and it does not work.

I’m having the same issue when posting @ or # in my search terms. I can’t figure out where the conflict is, so I had to revert to 5.13.0 for my app to run properly.