Toxic Bakery

Getting Google Auth Sub Tokens In Your Android Applications

by on Jul.23, 2010, under Android Development

Picture of the Android logo

Android Logo

For an app that I am working on I initially was going to ask the user for a username and password for their Google account and login with that information. However once I actually thought about how I would take a question like that, I quickly decided against that method. Instead I decided to look into what it would take to get a Google auth token to use as a login method to different services. Unfortunately this can only be done with Android 2.1 or greater however most phones should be on 2.1 here shortly so that hopefully won’t be a deal breaker for you.

Anyways, enough rambling from me I’m sure all you care about is the code.  The first thing you need to do is modify your Manifest file to allow access to the users phone account.

<uses-permission android:name="android.permission.MANAGE_ACCOUNTS"></uses-permission>
<uses-permission android:name="android.permission.GET_ACCOUNTS"></uses-permission>
<uses-permission android:name="android.permission.USE_CREDENTIALS"></uses-permission>
<uses-permission android:name="android.permission.INTERNET"></uses-permission>

That out of the way, you could use this code in conjunction with a loading dialog or any other method that works best for you..

	private String updateToken(boolean invalidateToken) {
		String authToken = "null";
		try {
			AccountManager am = AccountManager.get(context);
			Account[] accounts = am.getAccountsByType("com.google");
			AccountManagerFuture<Bundle> accountManagerFuture;
			if(activity == null){//this is used when calling from an interval thread
				accountManagerFuture = am.getAuthToken(accounts[0], "android", false, null, null);
			} else {
				accountManagerFuture = am.getAuthToken(accounts[0], "android", null, activity, null, null);
			}
			Bundle authTokenBundle = accountManagerFuture.getResult();
			authToken = authTokenBundle.getString(AccountManager.KEY_AUTHTOKEN).toString();
			if(invalidateToken) {
				am.invalidateAuthToken("com.google", authToken);
				authToken = updateToken(false);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return authToken;
	}

And there you have it. You now have a token that can be used with many of the Google services. This took a few hours of research on my part so hopefully this will save someone the trouble.

:, , , ,

13 Comments for this entry

  • Kris

    Hey man.

    Great code. Exactly what I was looking for.

  • RAGHU

    Hi,

    I am trying to get a authorized token for google finance…

    AccountManagerFuture future = manager.getAuthToken(account, “finance”, null, activity, null, null);

    account is the current the user selects, activity is my main activity…I am running this in a thread…

    Problem is it kicks off onPause, shows a dialog that allows the user to allow/deny access, then runs onResume…

    If the user selects allow, I want to load the portfolio…

    Any help would be appreciated…

    Thanks,
    Raghu

    Thanks,
    Raghu

  • tencent

    I wouldn’t run it from a thread, while you could do this from a thread I would instead save myself the headache and require the user to approve the usage of the finance token beforehand. Also you need to take into account that the token might not be valid and if you are doing this from a thread you now have additional error handling to try and shove in there. What I would do is right when the application launches explain to the user with a dialog that they will need to allow access to their Google finance account to make use of the application and allow them to accept or deny the request. Once they accept auto get the token and save in your settings that they have agreed. Now on future runs of the application you should run that getAuthToken function which will grab the cached auth token then immediately invalidate and and get a fresh token. The reasoning behind this is because you can’t know when or if the token is invalid until you get an error message back trying to use it. This method prevents you from having to add extra error catching every time you try to use the token and debugging will be easier because you will know for sure your token is valid.

    Also one key element here, once you get the token.. you can keep using it so you only need to make the auth token call one time and just keep a reference of it after that. From my research it seems they last about a month for Google services however I was never able to find any solid information other than that they do eventually expire so you are safer always assuming its expired when you launch your application.

    -Ian

  • RAGHU

    Ian,

    Thanks for the explanation. By the way, I am using android 3.0.

    If I run the getResult directly from the main thread, it give me an error “calling this from your main thread can lead to deadlock”.

    If I run it from a thread, it is only the first time I load portfolios for a new account, I have a problem. After that, it seems to run fine.

    Thanks,
    Raghu

  • tencent

    Sorry, I was mis leading in my answer. Yes you should launch this from a ‘thread’ however its all that thread should do and it should use a callback to immediately tell the the main thread what happened. Basically its like not having a thread because the thread really doesn’t do anything.

    Some sudo code..
    Thread thread;
    Dialog waitingDialog;
    int MY_TOKEN_RESPONSE = 0;
    String token;
    private void getToken() {
    waitingDialog = new IndeterminateDialog(“tell them they are waiting, this is my own custom class I dont remember how to use the stock android dialogs anymore sorry =P”);
    thread = new Thread(this);
    thread.start();
    }

    private Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
    waitingDialog.cancel();
    if(msg.what==MY_TOKEN_RESPONSE) {
    if(token != “”) {
    //save your token
    } else {
    throwAnError(“User either does not have a network connection or they denied the token request (possibly doesnt have a google account.. I forget if this is possible here.)”);
    }
    }
    }
    }

    //launch our thread and only grab the token and immediately stop working.
    public void run(){
    token = new FetchAuthToken();
    handler.sendEmptyMessage(MY_TOKEN_RESPONSE);
    }

  • RAGHU

    Ian,

    Here is my thread…This thread is invoked when I selected an account from the menu. getauthtoken cause onPause on my main activity, then I get the android dialog box to either allow/deny permission…bundle.getfuture actually throws a OperationCancel exception.
    then onresume is fired..

    What i would like to do, is get control after the dialog box to load my UI… The UI loads the second time I select the account from the menu.

    class LoadPortfoliosRunnable implements Runnable {

    private Account account;
    private Activity activity;

    public LoadPortfoliosRunnable(Activity activity, Account account) {
    this.activity = activity;
    this.account = account;
    }

    @Override
    public void run() {

    Bundle bundle = null;
    try {
    Log.d(LOG_TAG, “before getAuthToken”);
    manager.invalidateAuthToken(“com.google”, null);
    AccountManagerFuture future = manager.getAuthToken(account, “finance”, null, activity, null, null);
    Log.d(LOG_TAG, “future: ” + future);
    bundle = future.getResult();

    String auth = bundle.getString(AccountManager.KEY_AUTHTOKEN);
    Log.d(LOG_TAG, “token: ” + auth);
    } catch (Throwable e) {
    e.printStackTrace();
    }

    }
    }

    Thanks,
    Raghu

  • tencent

    Unfortunately I’m not really following you on the problem. Try shooting me an email at our developer account. (toxicbakery gmail)

  • lalbeg

    activity cannot be resolved to a variable

  • tencent

    The code posted is only partial and essentially just a guide for how to get it setup. You will have to launch this from an existing activity. One way you can get the activity is creating a var such as :

    Activity activity;

    Then have your onCreate() set

    activity = this;

  • Arpit

    Thanks, this was very useful :)

  • Piotr

    I’ve tried using it in an application, but it somehow didn’t work. Getting an auth token worked, but trying to invalidate it wouldn’t (calling with argument set to true).

    The symptom was that the method would throw an exception (IllegalStateException) saying that subsequent call would lead to a deadlock. Thing is, this only happens when minSdkVersion is set in manifest.

  • Piotr

    Forgot to post solution ;) Basicaly I used AsyncTask and it worked. I’m Android newbie so this might be actually a known solution but to me it was a revelation and good read on threading in Android ;)

  • tencent

    Sorry I missed your comments. I am glad to see you got it working. Yes you have to execute this in a thread as you are not allowed to run expensive tasks on the UI thread in Android.

Leave a Reply

*

Looking for something?

Use the form below to search the site:

Still not finding what you're looking for? Drop a comment on a post or contact us so we can take care of it!