Search code examples
androidoauthtumblrsignpost

Android Tumblr Oauth-signpost 401


Okay, so, I am making a Tumblr client for Android, I've been trying and failing to get OAuth working for about a week now. Here's how its going:

User fires up the app. Main activity's onCreate does this:

settings = getSharedPreferences(PREFS_NAME, 0);
authToken=settings.getString("OauthToken", "none");
authTokenSecret=settings.getString("OauthSecret", "none");
if(authToken=="none" || authTokenSecret=="none"){
    Intent i = new Intent(getApplicationContext(),Authentication.class);
    startActivity(i);
}

this launches an authentication activity which contains a WebView. That activity successfully gets the request token, and sends the WebView to the Tumblr login screen. The user is asked to allow access to their data by the app, they press Allow, and my WebViewClient catches the Callback Url, and does this with it:

String[] token = helper.getVerifier(url);
            if (token != null) {
                try {
                    String accessToken[] = helper.getAccessToken(token[1]);
                    editor.putString("OauthToken", accessToken[0]);
                    editor.putString("OauthSecret", accessToken[1]);
                    editor.commit();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            finish();

The helper class's getAccessToken and getVerifier look like this:

public String[] getVerifier(String myUrl) {
    // extract the token if it exists
    Uri uri = Uri.parse(myUrl);
    if (uri == null) {
        return null;
    }

    String token = uri.getQueryParameter("oauth_token");
    String verifier = uri.getQueryParameter("oauth_verifier");
    return new String[] { token, verifier };
}

public String[] getAccessToken(final String verifier)
        throws OAuthMessageSignerException, OAuthNotAuthorizedException,
        OAuthExpectationFailedException, OAuthCommunicationException {
    new Thread(new Runnable() {
        public void run() {
                try {
                    mProvider.retrieveAccessToken(mConsumer, verifier);
                } catch (OAuthMessageSignerException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (OAuthNotAuthorizedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (OAuthExpectationFailedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (OAuthCommunicationException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
        }
    }).start();
    return new String[] {
            mConsumer.getToken(), mConsumer.getTokenSecret()
    };
}

Then I finally go back to the main application screen and try to make my first API call, to get the most recent ten posts on the user's dashboard:

OAuthConsumer myConsumer = new CommonsHttpOAuthConsumer(MainView.authToken, MainView.authTokenSecret);
            HttpGet request = new HttpGet("http://api.tumblr.com/v2/user/dashboard?limit=10");
            myConsumer.sign(request);
            HttpClient httpClient = new DefaultHttpClient();
            HttpResponse response = httpClient.execute(request);
            HttpEntity entity = response.getEntity();
            BufferedReader reader = new BufferedReader(new InputStreamReader(entity.getContent()));
            String line;
            while ((line = reader.readLine()) != null) {
                builder.append(line);
            }

However, instead of getting a nice JSON response like I ought to be, I am getting this:

10-20 16:36:18.110: D/Result(22817): {"meta":{"status":401,"msg":"Not Authorized"},"response":[]}

So where did I go wrong? Thanks


Solution

  • I've successfully used signpost library with Appache HttpCommons GET/POST/PUTs.

    Firstly, I've launched the WebView for login purpose, using the following code (ActivityLogin.java):

    private static CommonsHttpOAuthConsumer consumer = new CommonsHttpOAuthConsumer(AppConfig.CONSUMER_KEY, AppConfig.CONSUMER_SECRET);
    private static OAuthProvider provider = new DefaultOAuthProvider (AppConfig.requestURL, AppConfig.accessURL, AppConfig.authURL);
    
    private void logMeIn() throws ...{
        String authUrl = provider.retrieveRequestToken(consumer,AppConfig.CALLBACK_URL);
        startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(authUrl)));
    }
    

    Then, I've used onNewIntent(Intent) for receiving OAuth callbacks from the previously launched Activity:

    AppConfig.java code snipet:

    /** OAuth Authorization URL  */
    public static final String authURL = mainOAuthUrl+"/authorize/?theme=android";
    
    /** OAuth Request URL    */
    public static final String requestURL = mainOAuthUrl+"/request/token/";
    
    /** OAuth Access URL     */
    public static final String accessURL = mainOAuthUrl+"/access/token/";
    
    /** OAuth CALLback URL*/
    public static final String CALLBACK_URL = "yourapp://twitt";
    

    ActivityLogin.java code snipet:

    protected void onNewIntent(Intent intent) {
        Uri uri = intent.getData();
        if (uri != null && uri.toString().startsWith(AppConfig.CALLBACK_URL)) {  
            String verifier = uri.getQueryParameter(OAuth.OAUTH_VERIFIER);  
    
            provider.retrieveAccessToken(consumer, verifier);
            Data.OAuthAccessKey = consumer.getToken();
            Data.OAuthAccessSecret = consumer.getTokenSecret();
        }
    
    }
    

    And then, my connection code looks like that:

    public HttpResponse sampleOauthConnect(String url) throws ...{
    
        /** setup some connection params */
        HttpContext context = new BasicHttpContext();
    
        HttpRequestBase request = new HttpGet(url);
    
        if (Data.OAuthConsumer == null)
            Data.OAuthConsumer = new CommonsHttpOAuthConsumer(AppConfig.CONSUMER_KEY, AppConfig.CONSUMER_SECRET);
    
        if (Data.OAuthAccessKey == null || Data.OAuthAccessSecret == null)
            throw new LoginErrorException(LoginErrorException.NOT_LOGGED_IN);
    
        Data.OAuthConsumer.setTokenWithSecret(Data.OAuthAccessKey, Data.OAuthAccessSecret);
    
        try {
            Data.OAuthConsumer.sign(request);
        } catch (OAuthMessageSignerException e) {
            throw new LoginErrorException(LoginErrorException.OAUTH_EXCEPTION, e);
        } catch (OAuthExpectationFailedException e) {
            throw new LoginErrorException(LoginErrorException.OAUTH_EXCEPTION, e);
        } catch (OAuthCommunicationException e) {
            throw new LoginErrorException(LoginErrorException.OAUTH_EXCEPTION, e);
        }
    
        HttpClient client = new DefaultHttpClient();
    
        /** finally execute this request */
        return client.execute(request, context);
    }
    

    I may have missed something during copy-paste, just tell me if this solution will work for you. I'm using singpost 1.2.1.1