Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using saved Dropbox authentication details on Android

In the Getting started article on Dropbox website they have a tutorial how to use Core API with Android to get started.

When the application launches for the first time, the user is asked to authenticate the software to use the users Dropbox account. After the authentication is successfully finished, you'll receive a pair of authentication strings, the key and a secret.

After the user has authenticated the application to use his or her Dropbox account I save the key and the secred using Android's SharedPreferences.

How do I use these saved values? I don't mean how I retrieve them using SharedPreferences but how I use these to prevent the need of reauthenticating the application again? On the Dropbox site they don't provide a way to use these. All they say is

The finishAuthentication() method will bind the user's access tokens to the session. You'll now be able to retrieve them via mDBApi.getSession().getAccessTokenPair().

You'll need these tokens again after your app closes, so it's important to save them for future access (though it's not shown here). If you don't, the user will have to re-authenticate every time they use your app. A common way to implement storing keys is through Android's SharedPreferences API.

like image 422
MikkoP Avatar asked Dec 20 '22 03:12

MikkoP


2 Answers

I had the same problem, The documentation is not great so I saw several related questions about it. The key to solve this problem is in the method isLinked() in the AndroidAuthSession class. I share my code so It might solve your doubts.

public class DropBoxInteractorImpl implements DropBoxInteractor {
    private DropboxAPI<AndroidAuthSession> mDropBoxApi;

    public DropBoxInteractorImpl(DropboxAPI<AndroidAuthSession> mDropBoxApi) {
        this.mDropBoxApi = mDropBoxApi;
    }

    @Override
    public void login(final Context context, final CloudServiceCallback cloudServiceCallback) {
        String accessToken = PrefUtils.getFromPrefs(context, KeysPref.DROPBOX_ACCESS_TOKEN, null);
        if (accessToken == null) {
            mDropBoxApi.getSession().startOAuth2Authentication(context);
        } else {
            mDropBoxApi.getSession().setOAuth2AccessToken(accessToken);
        }
    }

    @Override
    public void confirmLogin(Context context, final CloudServiceCallback cloudServiceCallback) {
        AndroidAuthSession session = mDropBoxApi.getSession();
        if (session.authenticationSuccessful()) {
            // Required to complete auth, sets the access token on the session
            session.finishAuthentication();
            String accessToken = mDropBoxApi.getSession().getOAuth2AccessToken();
            PrefUtils.saveToPrefs(context, KeysPref.DROPBOX_ACCESS_TOKEN, accessToken);
        }

        if (session.isLinked()) {
            cloudServiceCallback.loginSuccessful();
        } else {
            cloudServiceCallback.loginError();
            Timber.e("There was a problem login in!!");
        }
    }
}

I will explain it step by step.

  • First of all, I am using Dagger as dependency injection, that's why I get my mDropBoxApi in the constructor, but If you are not, just create the session always the same way as I am doing in this method.

    @Provides
    @Singleton
    public DropboxAPI<AndroidAuthSession> providesDropBoxService() {
        AppKeyPair appKeyPair = new AppKeyPair(Keys.DROPBOX_APP, Keys.DROPBOX_APP_SECRET);
        AndroidAuthSession session = new AndroidAuthSession(appKeyPair);
        return new DropboxAPI<AndroidAuthSession>(session);
    }
    
  • Now that you have your DropboxAPI object, you need to either startOAuth2Authentication' orsetOAuth2AccessToken` in case you have it already (saved form the last session). You can do that in onCreate (if it is an activity) or in onActivityCreated if it is a Fragment.

    @Override
    public void login(final Context context) {
        String accessToken = PrefUtils.getFromPrefs(context, KeysPref.DROPBOX_ACCESS_TOKEN, null);
        if (accessToken == null) {
            mDropBoxApi.getSession().startOAuth2Authentication(context);
        } else {
            mDropBoxApi.getSession().setOAuth2AccessToken(accessToken);
        }
    }
    
  • After that, in your onResume method (and here is where we are going to solve our problem) you check if the login was successful calling the function session.authenticationSuccessful(). This will return true ONLY in case you did the authentication process. If it is not null, either the login was not successful or your account is already LINKED. That's it, LINKED. How do you check that? Well as I said before, It is the key to solved this problem. What you need to check is if the session is already Linked calling session.isLinked() and voilà. It will tell you if you are successfully linked with the dropbox api or , in case it is false, there was a problem in the process.

    @Override
    public void confirmLogin(Context context, final CloudServiceCallback callback) {
        AndroidAuthSession session = mDropBoxApi.getSession();
        if (session.authenticationSuccessful()) {
            // Required to complete auth, sets the access token on the session
            session.finishAuthentication();
            String accessToken = mDropBoxApi.getSession().getOAuth2AccessToken();
            PrefUtils.saveToPrefs(context, KeysPref.DROPBOX_ACCESS_TOKEN, accessToken);
        }
    
        if (session.isLinked()) {
            callback.loginSuccessful();
        } else {
            callback.loginError();
            Timber.e("There was a problem login in!!");
        }
    }
    

I hope this solve you doubts about it, and If you have any question, please, don't hesitate to ask.

like image 107
jpardogo Avatar answered Jan 05 '23 11:01

jpardogo


The dropbox android JavaDoc seems to expand on what you need to do a little more, showing an alternative AndroidAuthSession constructor:

When a user returns to your app and you have tokens stored, just create a new session with them:

AndroidAuthSession session = new AndroidAuthSession(
     myAppKeys, myAccessType, new AccessTokenPair(storedAccessKey, storedAccessSecret));

I guess then you just have to instantiate a DropboxAPI object and you're good to go without the startAuthentication()... endAuthentication() etc.

DropboxAPI<AndroidAuthSession> mDBApi = new DropboxAPI<AndroidAuthSession>(session);

I haven't tried this out, but it's essentially the same thing that Greg was saying.

like image 29
RTF Avatar answered Jan 05 '23 11:01

RTF