Response Code 401 from "request token" api - Java Code


#1

I am trying to follow step by step instructions at https://dev.twitter.com/docs/auth/oauth to connect Twitter from Java code (not using any connection libraries)

I have tried my best for 2-3 days but something is terribly wrong in what I am doing. Please can someone advice?

package com.xxxx;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;

public class TwitterTest {

	static final String TwitterUri = "https://api.twitter.com/oauth/request_token";
	static final String TwitterClientID = "qU0D...................Wt1A";
	static final String TwitterClientSecret = "eQdRIZ..........................lP8oPUs";
	static final String TwitterRedirectUri = "http://www.amobs.co.uk/thandler.php";
	
	public static void main(String args[]){
		try{
			new TwitterTest().processTwitter();
		}catch(Exception ex){
			ex.printStackTrace();
		}
	}

	public void processTwitter() throws Exception {
		int millis = (int) System.currentTimeMillis() * -1;
		int time = (int) millis / 1000;
		//First, we sort all the parameters used in our request and formulate a signature base string. 
		String signatureBaseString = "POST&" + 
		URLEncoder.encode(TwitterUri, "UTF-8")+ 
		"&" + "oauth_callback%3D"+ URLEncoder.encode(TwitterRedirectUri, "UTF-8")+ 
		"%26oauth_consumer_key%3D"+ URLEncoder.encode(TwitterClientID, "UTF-8")+ 
		"%26oauth_nonce%3D"+ URLEncoder.encode(String.valueOf(millis), "UTF-8")+ 
		"%26oauth_signature_method%3D"+ URLEncoder.encode("HMAC-SHA1", "UTF-8")+ 
		"%26oauth_timestamp%3D"+ URLEncoder.encode(String.valueOf(time), "UTF-8")+ 
		"%26oauth_version%3D" + URLEncoder.encode("1.0", "UTF-8");

		System.out.println("Signature Base: "+signatureBaseString);

		//Our signing key is (notice the dangling ampersand at the end):
		String signingKey = TwitterClientSecret + "&";
		String signature = null;
		try {
			Mac mac = Mac.getInstance("HmacSHA1");
			SecretKeySpec secret = new SecretKeySpec(signingKey.getBytes(),
					"HmacSHA1");
			mac.init(secret);
			byte[] digest = mac.doFinal(signatureBaseString.getBytes());
			//We then use the composite signing key to create an oauth_signature from the signature base string
			signature = Base64.encodeBase64String(digest);
			System.out.println("The resultant oauth_signature is: " +signature);
		} catch (Exception ex1) {
			ex1.printStackTrace();
			System.exit(0);
		}

		//Now we just generate an HTTP header called "Authorization" with the relevant OAuth parameters for the request:
		String oAuthParameters = "OAuth " +
				"oauth_callback=\""+ URLEncoder.encode(TwitterRedirectUri, "UTF-8") + "\""
				+ ", oauth_consumer_key=\""+ URLEncoder.encode(TwitterClientID, "UTF-8") + "\""
				+ ", oauth_nonce=\""+ URLEncoder.encode(String.valueOf(millis), "UTF-8") + "\""
				+ ", oauth_signature=\""+ URLEncoder.encode(signature, "UTF-8") + "\""
				+ ", oauth_signature_method=\""+ URLEncoder.encode("HMAC-SHA1", "UTF-8") + "\""
				+ ", oauth_timestamp=\""+ URLEncoder.encode(String.valueOf(time), "UTF-8") + "\""
				+ ", oauth_version=\"" + URLEncoder.encode("1.0", "UTF-8")+ "\"";
		System.out.println("oAuth Parameters are " +oAuthParameters);

		//When Twitter.com receives our request, it will respond with an oauth_token, oauth_token_secret
		//SO LET ME SEE IF I AM LUCKY!!!
		URL url = new URL(TwitterUri);
		HttpURLConnection conn = null;
		try {
			conn = (HttpURLConnection) url.openConnection();
			conn.setDoOutput(true);
			conn.setRequestMethod("POST");
			//Set the oAuth params in header
			conn.addRequestProperty("Authorization", oAuthParameters);
			//Shall I set something in body?
			String bodyParams = 
					"oauth_callback="+ URLEncoder.encode(TwitterRedirectUri, "UTF-8")
					+ "&oauth_consumer_key="+ URLEncoder.encode(TwitterClientID, "UTF-8") 
					+ "&oauth_nonce="+ URLEncoder.encode(String.valueOf(millis), "UTF-8")
					+ "&oauth_signature=" + URLEncoder.encode(signature, "UTF-8")
					+ "&oauth_signature_method="+URLEncoder.encode("HMAC-SHA1", "UTF-8") 
					+ "&oauth_timestamp="+URLEncoder.encode(String.valueOf(time), "UTF-8")
					+ "&oauth_version=" + URLEncoder.encode("1.0", "UTF-8");
			System.out.println("Parameters for body are " +oAuthParameters);
			OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream(), "UTF-8");
			writer.write(bodyParams);
			writer.flush();
			conn.connect();

			// Get Response
			InputStream is = conn.getInputStream();
			BufferedReader rd = new BufferedReader(new InputStreamReader(is));
			String line;
			StringBuffer dataBack = new StringBuffer();
			while ((line = rd.readLine()) != null) {
				dataBack.append(line);
				dataBack.append('\r');
			}
			rd.close();
		} catch (Exception e) {
			System.err.println("And blasted!");
			e.printStackTrace();
		} finally {
			if (conn != null) {
				conn.disconnect();
			}
		}

	}

}

#2

I think you have something wrong in getting base string.
The result of URLEncoder.encode(TwitterRedirectUri, “UTF-8”) is different from the result from twitter.
You should code like this
URLEncoder.encode(URLEncoder.encode(TwitterRedirectUri, “UTF-8”), “UTF-8”)
That’s because this callback url also need encode.

From Twitter:
Instead, the URL is URL-encoded and considered a single string.

Hopes this can help you!


#3

Did you find solution?
I have this problem too.


#4

i don’t know exactly, but i think you don’t need do OutputStream if you use POST Header “Authorization”.
see this https://dev.twitter.com/docs/api/1/post/oauth/request_token


#5

Im actually getting 401 errors myself http://stackoverflow.com/questions/7247956/twitpic-oauth-echo-java-j2ee


#6

Same issue, if any one had found a fix, pls provide the inputs.
Really appreciate your help.


#7

i dont know


#8

int timestamp = (int)((System.currentTimeMillis())/1000);
Worked for me!


#9

int timestamp = (int)((System.currentTimeMillis())/1000);
Worked for me!


#10

Thanks!


#11

Finally after dealing with this error since 2 dyas here is wat i found out to make it work…

  1. Call back url must be encoded additionally (Twice) as pointed out by @LeslieCNT only for generating the BaseString.

2.Call back url used while setting the Authorization header should be encoded only once.


#12

Hi All… I too facing same issue.

tried with following modifications.

  1. tried with encoding the call back url twice.
  2. timestamp as mentioned above by vaishaknair
  3. oauth_nonce = RandomStringUtils.randomAscii(32);
  4. without output stream

Anyone can help me?


#13

Will setting proxy solve the problem?


#14

I have same problem too and hope someone could help me to resolve this problem.


#15

I simply switch to:
https://api.twitter.com/oauth2/token
instead of
https://api.twitter.com/oauth/request_token
and it works.

I think the settings on my OAuth settings page are wrong (maybe Twitter Dev webapp has a bug ??).
For me it says:
Request token URL https://api.twitter.com/oauth/request_token
as you are using aboce.

I got the working URL from
https://dev.twitter.com/docs/api/1.1/post/oauth2/token