How to update Twitter status with Oauth authentication in core Java

java

#1

I’ve been receiving HTTP response code 400, error code 215, ‘Bad Authentication data’ when trying to post a Twitter update. From the Twitter developer app, I have an oauth_consumer_key & oauth_token along with oauth_consumer_secret & oauth_token_secret for the Twitter account.

public void doPOSTTweet() throws IOException {		
	
    // Build Signature base string

    String message = "Hey Ladies and Gentlemen a signed OAuth request";
    int timeint 	= (int) (System.currentTimeMillis() / 1000);
    String oauth_timestamp = Integer.toString(timeint);
    int nonce	= (int) (Math.random() * 100000000);
    String oauth_nonce 	= Integer.toString(nonce);
	
    String url = POST_TWITTER_URL;

    // Parameters
    String params = "include_entities=true&oauth_consumer_key="+oauth_consumer_key
        +"&oauth_nonce="+oauth_nonce+"&oauth_signature_method=HMAC-SHA1&oauth_timestamp="+oauth_timestamp
        +"&oauth_token="+oauth_token+"&oauth_version=1.0&status="+encodeURIComponent(message);
	
    String signature_base_string = "POST" + "&" + encodeURIComponent(url) + "&" + encodeURIComponent(params);

    // Getting a signing key
    String oauth_signature	= generateSignature(signature_base_string, oauth_consumer_secret, oauth_token_secret);
	
    URL obj = new URL(url);
	
    HttpsURLConnection conn = (HttpsURLConnection) obj.openConnection();
    conn.setRequestMethod("POST");
    conn.setRequestProperty("User-Agent", USER_AGENT);
	
    // set POST headers
    conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
    conn.setRequestProperty("Authorization", "OAuth oauth_consumer_key=\""+oauth_consumer_key
    		+"\", oauth_nonce=\""+oauth_nonce
    		+"\", oauth_signature=\""+oauth_signature
    		+"\", oauth_signature_method=\"HMAC-SHA1\", oauth_timestamp=\""+oauth_timestamp
    		+"\", oauth_token=\""+oauth_token+"\", oauth_version=\"1.0\"");
 
    // POST output		
    conn.setDoOutput(true);
    OutputStream os = conn.getOutputStream();
    os.write(params.getBytes());
    os.flush();
    os.close();

    int responseCode = conn.getResponseCode();
    System.out.println("Twitter POST Response Code :: " + responseCode);

// ....

}

The oauth_signature is being generated with these functions:

public String generateSignature(String signatureBaseStr, String oAuthConsumerSecret, String oAuthTokenSecret) {  
    byte[] byteHMAC = null;  
    try {  
      Mac mac = Mac.getInstance("HmacSHA1");  
      SecretKeySpec spec;  
      if (null == oAuthTokenSecret) {  
        String signingKey = encodeURIComponent(oAuthConsumerSecret) + '&';  
        spec = new SecretKeySpec(signingKey.getBytes(), "HmacSHA1");  
      } else {  
        String signingKey = encodeURIComponent(oAuthConsumerSecret) + '&' + encodeURIComponent(oAuthTokenSecret);  
        spec = new SecretKeySpec(signingKey.getBytes(), "HmacSHA1");  
          }  
          mac.init(spec);  
          byteHMAC = mac.doFinal(signatureBaseStr.getBytes());  
        } catch (Exception e) {  
          e.printStackTrace();  
        }  
        return Base64.encode(byteHMAC.toString());  
}  

public static String encodeURIComponent(String s) {
    String result;

    try {
        result = URLEncoder.encode(s, "UTF-8")
                .replaceAll("\\+", "%20")
                .replaceAll("\\&", "%26");
    } catch (UnsupportedEncodingException e) {
        result = s;
    }

    return result;
}

The parameter string is:

include_entities=true&oauth_consumer_key=xxPPDD9m81ZIVbM5my5mc5Vgw
&oauth_nonce=49123012&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1539221210
&oauth_token=0000000619224240130-2ZZZjFqaSddjixLbBcPfYdbniQLMXX&oauth_version=1.0
&status=Hey%20Ladies%20and%20Gentlemen%20a%20signed%20OAuth%20request

The signature_base_string :

POST&https%3A%2F%2Fapi.twitter.com%2F1.1%2Fstatuses%2Fupdate.json
&include_entities%3Dtrue%26oauth_consumer_key%3DxxPPDD9m81ZIVbM5my5mc5Vgw
%26oauth_nonce%3D49123012
%26oauth_signature_method%3DHMAC-SHA1
%26oauth_timestamp%3D1539221210%26oauth_token%3D0000000619224240130-2ZZZjFqaSddjixLbBcPfYdbniQLMXX%26oauth_version%3D1.0
%26status%3DHey%2520Ladies%2520and%2520Gentlemen%2520a%2520signed
%2520OAuth%2520request

The oauth_signature is: W0JAMTBkZDcwMTg=

When posted, the HTTP response code is 400 with a JSON response:

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

I have manually recreated this post with Postman, entering the same info:

Twitter Post

The error message is the same from Postman. I’ve confirmed the oauth keys with the Twitter app page, and all is identical. Any ideas on troubleshooting this? Is there a proper syntax and/or order that is missing?


#2

I recommend a couple of things…

First off, have you seen this OAuth library? https://github.com/scribejava/scribejava
It might help you with your setup.

We also have identified that Postman doesn’t handle some OAuth 1.0a dependencies properly. Have you tried playing around with Insomnia at all?


#3

String oauth_signature = generateSignature(signature_base_string, oauth_consumer_secret, oauth_token_secret);
I think in this line, you need an extra step of encoding the oauth_signature string:
oauth_signature = encodeURIComponent(oauth_signature);
and use this afterwards.


#4