Search code examples
scalaplayframeworkplayframework-2.0twitter-oauthsignpost

How can I do a Twitter Reverse Auth In Scala Play Framework?


I'm writing a play application (in scala) and I'm trying to perform the reverse-auth step that is outlined by twitter here: https://dev.twitter.com/docs/ios/using-reverse-auth

The step sounds like an ordinary RetrieveRequestToken to https://api.twitter.com/oauth/request_token with the additional parameter of setting the x_auth_mode=reverse_auth

THe play framework makes use of Sign-Post (https://code.google.com/p/oauth-signpost/) and I was wondering how I can leverage the WS library and Sign-Post to make this happen.

Here is what I came up with:

val KEY = ConsumerKey(Play.configuration.getString("twitter.consumer.key").getOrElse("XXXX"),               Play.configuration.getString("twitter.consumer.secret").getOrElse("XXXX"))

  def reverse = Action.async {
    val oauth_calc = OAuthCalculator(KEY,  RequestToken("","") )
    oauth_calc.setSigningStrategy(new oauth.signpost.signature.AuthorizationHeaderSigningStrategy )
    var reverse_request : Future[Response] = WS.url("https://api.twitter.com/oauth/request_token").sign(oauth_calc)
         .post(Map("x_auth_mode" -> Seq("reverse_auth")))     
      reverse_request.map{
        response => {
          Logger.debug(response.body)
          Ok("Here")
        }
      }
  }

I'm getting however "Failed to validate oauth signature and token"


Solution

  • So I found part of the answer here: https://stackoverflow.com/a/20635782/143733 I had to use the apache default HttpClient as there seemed no way to do it in Play WS class or Sign-Post.

    Here is the final async implementation I came up with:

    object Twitter extends Controller {
    
      val KEY = ConsumerKey(Play.configuration.getString("twitter.consumer.key").getOrElse("XXXX"), 
                            Play.configuration.getString("twitter.consumer.secret").getOrElse("XXXX"))
    
      val TWITTER_SERVICE_INFO = ServiceInfo(
        "https://api.twitter.com/oauth/request_token",
        "https://api.twitter.com/oauth/access_token",
        "https://api.twitter.com/oauth/authorize", KEY)
    
      val TWITTER = OAuth(TWITTER_SERVICE_INFO,false)
    
      /***
       * The following is the reverse oauth step outlined by twitter 
       */
      def reverse = Action.async {
    
        val client = new DefaultHttpClient();
        val params = new java.util.ArrayList[BasicNameValuePair](1)
        params.add(new BasicNameValuePair("x_auth_mode", "reverse_auth"))
        val consumer = new CommonsHttpOAuthConsumer(KEY.key, KEY.secret)
        val post = new HttpPost(TWITTER_SERVICE_INFO.requestTokenURL)
        post.addHeader("Content-Type", "application/x-www-form-urlencoded")
        post.setEntity(new UrlEncodedFormEntity(params))
        consumer.sign(post)
    
        val futureBodyString: Future[String] = future {
          val response = client.execute(post)
          EntityUtils.toString(response.getEntity())
        }
    
        futureBodyString.map {
          body => {
            Ok(body)
          }
        }
    
      }
    
    
    }