I am trying to allow Android users to post to their Tumblr blogs using my app. I am able to launch Tumblr, enter my username and password, and log in, however the problem is the Access Token I receive appears to be invalid (I get a 401 - Unauthorized when I use it with any of Tumblr's API calls).
Below is the code I am using. I am able to authenticate with Twitter, but Tumblr is giving me difficulties. If anyone has any ideas, suggestions, or improvements, they would be much appreciated. Thanks!
public final class TumblrWebView extends Activity {
private final String TAG = getClass().getSimpleName();
OAuth10Service service;
public final static String PARAMETER_CONSUMER_KEY = "CONSUMER_KEY";
public final static String PARAMETER_CONSUMER_SECRET = "CONSUMER_SECRET";
public final static String PARAMETER_CALLBACK_URL = "CALLBACK_URL";
private String consumerKey;
private String consumerSecret;
private String callbackUrl;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.web_view);
/*
* Get params
*/
Intent intent = getIntent();
consumerKey = intent.getStringExtra(PARAMETER_CONSUMER_KEY);
consumerSecret = intent.getStringExtra(PARAMETER_CONSUMER_SECRET);
callbackUrl = intent.getStringExtra(PARAMETER_CALLBACK_URL);
service = OAuthService.newInstance(new TumblrApi(), consumerKey, consumerSecret, new OAuth10ServiceCallback() {
@Override
public void onOAuthAccessTokenReceived(OAuth10Token token) {
complete(token);
Log.i(TAG, "Access token recieved");
// System.out.println("token recieved " + token.getAccessToken());
// System.out.println("token recieved " + token.getUserSecret());
}
@Override
public void onOAuthRequestTokenReceived() {
loadWebView();
Log.i(TAG, "Request token recieved");
}
@Override
public void onOAuthRequestTokenFailed(HootResult result) {
Log.e(TAG, "Token request failed " + result.getException());
}
@Override
public void onOAuthAccessTokenFailed(HootResult result) {
Log.e(TAG, "Token access failed " + result);
}
});
service.start();
}
@SuppressLint("SetJavaScriptEnabled")
private void loadWebView() {
final WebView webview = (WebView) findViewById(R.id.web_view);
webview.getSettings().setJavaScriptEnabled(true);
webview.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
// Checking for our successful callback
if(url.startsWith(callbackUrl)) {
webview.setVisibility(View.GONE);
Log.d(TAG, "token url " + url + " " + service.getOAuthAccessToken(url));
} else {
Log.d(TAG, "token url");
}
return super.shouldOverrideUrlLoading(view, url);
}
});
webview.loadUrl(service.getAuthorizeUrl());
}
private void complete(OAuth10Token token) {
Intent resultIntent = new Intent();
resultIntent.putExtra(TumblrUtils.PREF_TUMBLR_ACCESS, token.getAccessToken());
resultIntent.putExtra(TumblrUtils.PREF_TUMBLR_SECRET, token.getUserSecret());
setResult(RESULT_OK, resultIntent);
finish();
}
}
EDIT: A helper class
public class TumblrUtils {
// Consumer Key and Secret
private static final String TUMBLR_CONSUMER_KEY = "{ ENTER TUMBLR CONSUMER KEY }";
private static final String TUMBLR_CONSUMER_SECRET = "{ ENTER TUMBLR CONSUMER SECRET }";
// Callback URL
private static final String TUMBLR_CALLBACK_URL = "http://example.com";
// Request Code
public static final int TUMBLR_REQUEST_CODE = 87; /* 87 - TR */
// Preference Constants
public static final String PREF_TUMBLR_USER = "tumblr_user";
public static final String PREF_TUMBLR_ACCESS = "tumblr_access_token";
public static final String PREF_TUMBLR_SECRET = "tumblr_secret_token";
public static final String TUMBLR_REQUEST_URL = "http://www.tumblr.com/oauth/request_token";
public static final String TUMBLR_ACCESS_URL = "http://www.tumblr.com/oauth/access_token";
public static final String TUMBLR_AUTHORIZE_URL = "http://www.tumblr.com/oauth/authorize";
private static OAuthConsumer tumblrConsumer;
private static String tumblrHost;
private static String tumblrToken;
private static String tumblrTokenSecret;
private static String getConsumerKey() {
return TUMBLR_CONSUMER_KEY;
}
private static String getConsumerSecret() {
return TUMBLR_CONSUMER_SECRET;
}
private static String getCallbackUrl() {
return TUMBLR_CALLBACK_URL;
}
public static String getRequestUrl() {
return TUMBLR_REQUEST_URL;
}
public static String getAccessUrl() {
return TUMBLR_ACCESS_URL;
}
public static String getAuthorizeUrl() {
return TUMBLR_AUTHORIZE_URL;
}
public static OAuthConsumer getTumblrConsumer() {
return tumblrConsumer;
}
public static String getTumblrHost() {
return tumblrHost;
}
public static void setTumblrHost(String host) {
TumblrUtils.tumblrHost = host;
}
public static String getTumblrToken() {
return tumblrToken;
}
public static String getTumblrTokenSecret() {
return tumblrTokenSecret;
}
public static Intent getTumblrIntent(Context activity) {
Intent TumblrIntent = new Intent(activity, TumblrWebView.class);
TumblrIntent.putExtra("CONSUMER_KEY", getConsumerKey());
TumblrIntent.putExtra("CONSUMER_SECRET", getConsumerSecret());
TumblrIntent.putExtra("CALLBACK", getCallbackUrl());
return TumblrIntent;
}
public static OAuthConsumer saveTumblrResult(SharedPreferences settings,
String access_token, String secret_token) {
Editor editor = settings.edit();
editor.putString(PREF_TUMBLR_ACCESS, access_token);
editor.putString(PREF_TUMBLR_SECRET, secret_token);
editor.commit();
return saveTumblrResult(access_token, secret_token);
}
public static OAuthConsumer saveTumblrResult(String stringExtra1, String stringExtra2) {
tumblrToken = (stringExtra1);
tumblrTokenSecret = (stringExtra2);
tumblrConsumer = new CommonsHttpOAuthConsumer(
getConsumerKey(), getConsumerSecret());
tumblrConsumer.setTokenWithSecret(
tumblrToken, tumblrTokenSecret);
return tumblrConsumer;
}
}
EDIT: TumblrWebActivity - startActivityForResult
startActivityForResult(
TumblrUtils.getTumblrIntent(Settings_ShareSettings.this),
EDIT: TumblrWebActivity - onActivityResult
TumblrUtils.TUMBLR_REQUEST_CODE);
TumblrUtils.saveTumblrResult(mPrefs,
data.getStringExtra(TumblrUtils.PREF_TUMBLR_ACCESS),
data.getStringExtra(TumblrUtils.PREF_TUMBLR_SECRET));
new TumblrTask("https://api.tumblr.com/v2/user/info").execute();
EDIT: GetUserInfo - AsyncTask
private final class TumblrTask extends AsyncTask<String, Void, String> {
String url;
public TumblrTask(String url) {
this.url = url;
}
@Override
protected String doInBackground(String... params) {
String result = "";
HttpClient httpclient = GlobalContext.getHttpClient();
HttpRequestBase request = new HttpGet(url);
try {
TumblrUtils.getTumblrConsumer().sign(request);
} catch (OAuthMessageSignerException e) {
e.printStackTrace();
} catch (OAuthExpectationFailedException e) {
e.printStackTrace();
} catch (OAuthCommunicationException e) {
e.printStackTrace();
}
try {
HttpResponse response = httpclient.execute(request, GlobalContext.getLocalContext());
HttpEntity entity = response.getEntity();
InputStream instream = entity.getContent();
result = GlobalContext.convertStreamToString(instream);
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
@Override
protected void onPostExecute(String result) {
try {
JSONObject jObject = new JSONObject(result.trim());
System.out.println(jObject);
if(jObject.has("response")) {
JSONObject jResponse = jObject.getJSONObject("response");
System.out.println(jResponse);
if(jResponse.has("user")) {
JSONObject jUser = jResponse.getJSONObject("user");
System.out.println(jUser);
tumblr_name = jUser.getString("name");
TumblrUtils.saveTumblrResult(mPrefs, tumblr_name);
tvTumblr.setText(tumblr_name);
ibTumblr.setSelected(true);
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
EDIT: NOTE: Requires AndrOAuth
As it turns out, the Access Token and Access Token Secret returned were valid. The problem was that I was not signing the request with the Access Token Secret.