Tumblr Xauth Android - 400 Bad Request Error

2.5k views Asked by At

I am trying to use Xuath with Tumblr. I have already emailed the Tumblr Support team to enable Xuath for my app and they obliged. However, while trying to retrieve the user key and secret, I continually get a '400: Bad Request' error. I couldn't find a way of debugging a bad request.

The following is the code: (note- this code has been developed from snippets available across the web)

private final String CONSUMER_KEY = "mdMFLrprZGnRw4XO736GXcXP8huxaxTT5z1nlxDK38GbyWlW38";
private final String CONSUMER_SECRET = "VOpRNqKSLjhD3bR8vw4MorXgGc7lkT2FtBZr9xDchA5AvfscUI";

private final String ACCESS_URL = "https://www.tumblr.com/oauth/access_token";
private final String XAUTH_MODE = "client_auth";
private final String SIGNATURE_METHOD = "HMAC-SHA1";
private final String OAUTH_VERSION = "1.0";


private EditText mEmailAddress;
private EditText mPassword;
private Button mLogInButton;



@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.tumblr_layout);

    mEmailAddress = (EditText) findViewById(R.id.email_tumblr);
    mPassword = (EditText) findViewById(R.id.passowrd_tumblr);
    mLogInButton =  (Button) findViewById(R.id.tumblr_login_button);

    mLogInButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            String email = mEmailAddress.getText().toString();
            String password= mPassword.getText().toString();



            String oauth_nonce = a64BitRandomString();
            String oauth_timestamp = getTimeStamp();


            String signatureBaseString =
                    "POST"
                    + "&"
                    + URLEncoder.encode(ACCESS_URL)
                    + "&"
                    + URLEncoder.encode("oauth_consumer_key=" + URLEncoder.encode(CONSUMER_KEY))
                    + URLEncoder.encode("&" + "oauth_nonce=" + URLEncoder.encode(oauth_nonce))
                    + URLEncoder.encode("&" + "oauth_signature_method=" + URLEncoder.encode(SIGNATURE_METHOD))
                    + URLEncoder.encode("&" + "oauth_timestamp=" + URLEncoder.encode(oauth_timestamp))
                    + URLEncoder.encode("&" + "oauth_version=" + URLEncoder.encode(OAUTH_VERSION))
                    + URLEncoder.encode("&" + "x_auth_username=" + URLEncoder.encode(email))
                    + URLEncoder.encode("&" + "x_auth_password=" + URLEncoder.encode(password))
                    + URLEncoder.encode("&" + "x_auth_mode=" + URLEncoder.encode(XAUTH_MODE));


            String oauth_signature= getSignature(signatureBaseString, "HmacSHA1",
                    CONSUMER_SECRET+"&");

            try {
                String headerValue = "OAuth " +
                        "oauth_nonce=\""+oauth_nonce+"\"," +
                        "oauth_signature_method=\""+SIGNATURE_METHOD+"\"," +
                        "oauth_timestamp=\""+oauth_timestamp+"\"," +
                        "oauth_consumer_key=\""+CONSUMER_KEY+"\"," +
                        "oauth_signature=\""+URLEncoder.encode(oauth_signature,"UTF-8")+"\"," +
                        "oauth_version=\""+OAUTH_VERSION+"\"";

                HttpPost httppost = new HttpPost(ACCESS_URL
                        +"?x_auth_username="+URLEncoder.encode(email)
                        +"&x_auth_password="+URLEncoder.encode(password)
                        +"&x_auth_mode="+URLEncoder.encode(XAUTH_MODE));    

                httppost.setHeader("Host","https://www.tumblr.com");
                httppost.setHeader("Content-Type","application/x-www-form-urlencoded");
                httppost.setHeader("Authorization",headerValue);


                // Execute HTTP Post Request
                HttpClient httpclient = new DefaultHttpClient();
                HttpResponse response = httpclient.execute(httppost); // **I get the 401 error here**
                StatusLine statusLine = response.getStatusLine();
                if (statusLine.getStatusCode() == HttpStatus.SC_OK) {
                HttpEntity entity = response.getEntity();
                String jString= EntityUtils.toString(entity);
                Log.d("TUMBLR - Value(s):", jString);
                }

            } catch (UnsupportedEncodingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (ParseException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

        }
    });

}

private String a64BitRandomString() {
    StringBuffer sb = new StringBuffer();
    Random generator = new Random();

    for (int i = 0; i < 32; i++) {
        Integer r = generator.nextInt();
        if (r < 0) {
            r = r * -1;
        }
        r = r % 16;

        sb.append(Integer.toHexString(r));
    }

    return sb.toString();
}


private String getTimeStamp(){
    long seconds = (long) (System.currentTimeMillis()/1000.0);
    String secondsString = String.valueOf(seconds);
    return secondsString;
}

private String getSignature(String base, String mode, String secret) {
    String signature = null;


    SecretKeySpec key;
    try {
        key = new SecretKeySpec((secret).getBytes("UTF-8"), mode);

        Mac mac = Mac.getInstance(mode);
        mac.init(key);

        byte[] bytes = mac.doFinal(base.getBytes("UTF-8"));

        signature = new String(Base64.encode(bytes,Base64.NO_WRAP));
    }
    catch (UnsupportedEncodingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (InvalidKeyException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    return signature;
}

I understand that it would be extremely difficult to identify the exact mistake here. But, I would be glad if someone could provide suggestions or point me in the right direction.

String headerValue has the following value:

OAuth oauth_nonce="8d0e6e03ae2424260ddd647d5afba70d",oauth_signature_method="HMAC-SHA1",oauth_timestamp="1327434351943",oauth_consumer_key="mdMFLrprZGnRw4XO736GXcXP8huxaxTT5z1nlxDK38GbyWlW38",oauth_signature="cYNStrfA%2F2lTaGKL8pxWHpzSq9w%3D",oauth_version="1.0"

So, it seems to be in the right format. Would it help to include newline characters in the string?

2

There are 2 answers

0
Abhijit On BEST ANSWER

After tearing my hair apart for a few days, it turns out that I was sending too much of information in the HTTP post body (hence, a bad request error was being thrown back at me). All that was necessary is the following set of parameters:

x_auth_username (the user's email address), x_auth_password, and x_auth_mode=client_auth

Also, I should be making use of the robust Oauth Library functions instead of trying to write my own functions using my limited knowledge. In my defense, the documentation was never really clear enough regardless. A lesson very well learnt - about re-suing code and using common sense. For those who might be wondering if there is a legit java client for TUMBLR - here is the github link: https://github.com/nsheridan/tumblr-java. I assure you that this is the best piece of code for Tumblr that I have come across.

0
Sanyam On

After a lot of searching, found following code somewhere for twitter -

            // replace with your username and password
            String password = “passwd”;
            String userName = “[email protected]”;

            HttpPost httppost = new HttpPost("https://www.tumblr.com/oauth/access_token");
            CommonsHttpOAuthConsumer consumer = new CommonsHttpOAuthConsumer(
                    CONSUMER_KEY, CONSUMER_SECRET);     

            List<BasicNameValuePair> reqParams = Arrays.asList(
                    new BasicNameValuePair("x_auth_username", userName),
                    new BasicNameValuePair("x_auth_password", password),
                    new BasicNameValuePair("x_auth_mode", "client_auth"));

            AuthToken authToken = null;
            try {
                UrlEncodedFormEntity entity = new UrlEncodedFormEntity(reqParams, HTTP.UTF_8);
                httppost.setEntity(entity);
                consumer.sign(httppost);
                HttpClient httpclient = new DefaultHttpClient();
                HttpResponse response = httpclient.execute(httppost);

                StatusLine statusLine = response.getStatusLine();
                if (statusLine.getStatusCode() == HttpStatus.SC_OK) 
                {
                    InputStream data = response.getEntity()
                            .getContent();

                    final char[] buffer = new char[0x10000];
                    StringBuilder out = new StringBuilder();
                    Reader in = new InputStreamReader(data, HTTP.UTF_8);
                    int read;
                    do {
                        read = in.read(buffer, 0, buffer.length);
                        if (read > 0)
                            out.append(buffer, 0, read);
                    } while (read >= 0);
                    in.close();
                    String responseString = out.toString(); 

                    String[] splitResponse = StringUtils.split(responseString, "&");
                    String accessTokenSecret = getParameter(splitResponse, "oauth_token_secret");
                    String accessToken = getParameter(splitResponse, "oauth_token");

                }
            } catch (UnsupportedEncodingException e) {
            } catch (OAuthMessageSignerException e) {
            } catch (OAuthExpectationFailedException e) {
            } catch (OAuthCommunicationException e) {
            } catch (Exception e) {
            }