105 comments on “Write your own Android Authenticator

  1. I do not understand this. Everything I know on web is self taught. Call me illiterate. Please explain in layman’s terms

    • Hey,

      Some of the stuff here requires prior knowledge.

      Explaining every concept presented here will get this post be at least 3 times bigger.

      I’d recommend reading about OAuth2, to understand authentication methods, and also the links I refer to on this post (they provide further information about the subject).

      Good luck!

  2. Hi!
    First of all I have to say, that this piece of code is really really helpful. Thank you so much for that.

    I only stumbled across one issue.
    1. I added an account for my first app, which worked like a charm.
    2. I reused the same Service for my second app: Getting and invalidating tokens works as expected, also the invalidating part. The only thing I am struggeling with is the “Add Account” – part.
    If I press on the button nothing happens. I think there is something wrong with binding the service, but I have not figured out what the issue really is.

    Maybe you can me point me in the right direction, why I am not able to open up the “Sign – In” – page in my second app.

    Other than that, thanx for your code and the awesome explanation.
    br MikeT

      • Perfect!
        What a fast reply. That little change did the trick! Thanx, you saved me from getting millions of grey hair :)
        All the best. And keep up the good work.

    • Hey Mike, below it sounds like you were able to make this work by changing authenticator.xml. Could you explain what change you made?

  3. You can 2-way encrypt the password you’re storing in the AccountManager with a device-specific key. It’s recommended that you do that with the auth_token as well, for the same reason that storing the plain text password is insecure. That way, the password and auth_token are never known by the AccountManager. There’s a Android dev blog post on encryption.

  4. I’ve been searching for an explanation like this. I’ve a little question, if i want that the first time that i open the app, ask me to log in and if the log in is succesfull then open another activity, i need to put the authenticator activity like the launcher activity?

    • No, that’s what’s cool about this method.

      You can start your main activity and try to get an auth token. If there isn’t one – the framework will automatically raise the authentication activity and return the response back to your main activity after the user has successfully logged in.

      • Hi, i trying to get an auth token inside my main activity, but nothings happen

        mAccountManager.getAuthTokenByFeatures(SyncConstants.ACCOUNT_TYPE,
        SyncConstants.AUTHTOKEN_TYPE, null, this, null, null, null, null);

        the application never display the login activity automatically, what do you think?

  5. Thanks for the great explanation! It’s by far the best i found on the net.
    I do have a problem trying to use the code you provided: I get an ActivityNotFoundException for”:
    com.udinic.accounts_authenticator_example/com.udinic.accounts_authenticator_example.authentication.LoginActivity”
    – when trying to add a new account. I can’t find any place that LoginActivity is invoked, and I haven’t changed the code.
    In a previous post you suggested looking at the values in the authenticator.xml. At what values specifically ?

    • The LoginActivity is probably invoked by the AccountAuthenticator itself. Check there. You need to declare that activity in your app to make it work.

  6. “2. First in, first served ”

    I created a library project and created the full suite, the authenticator, the activity and the service (almost like the good the bad the ugly :P).

    I’m using the library (a.k.a authlib) in two different projects. I installed both apps in the device.

    Almost ALWAYS, only the first app’s “addAccount” from the Authenticator class gets called. Anytime i open the second app and try to invoke the account adding flow, it doesn’t seem to bind properly. I’m not sure why. Any help would be greatly appreciated.

    p.s: I’m trying to use 1 account for two apps. But the “adding of the user” should be possible from either of the apps and should not be dependant on the sequence of the installation.

    • The order of the selected authenticator is OS implementation and unfortunately cannot be changed.

      HOWEVER,

      I believe you can do what you need following these steps:

      1. On the authenticator project, create 2 sign-up activities, having their own log-in flow according to what you need for each app using this library.
      2. When calling the account manager to add an account, for any of the 2 apps, you can pass an “options” extra to the method. Pass “APP1″ or “APP2″ in the Bundle.
      3. On the authenticator’s addAccount() method – read the “options” extra and start the appropriate sign-up flow.

      I haven’t tried it, but I think it can work.

      If you do try this – please report back for other people to learn.

  7. Hi, thanks for sharing this. It helps me a lot to understand the flow.
    There is one thing I do not understand. I understand that in OAuth2.0 you have to provide an client_id to get an accesstoken. It seems that you are not using this. How can this be communicated via the account manager to the authenticator?

    • The algorithm to acquire the auth token from the server is up to you. If you need to pass a client_id, API key or a CAPTCHA – that’s your responsibility to do that on the authenticator when acquiring the auth token. After that – you just store the auth token in the account manager as any other authenticator will do.

  8. Hi. When i tried both the source code project and the google play sample, the authentication is successful, but always when i access the Udinic account configuration my phone crashes and restarts… In the Logcat it tells about some ‘Error inflating class Switchpreference’. What i am doing wrong?

    • You probably running this example on an unsupported API level device. Switchpreference exists since API 14, you’re probably running this on device <ICS.

  9. Pingback: Write your own Android Sync Adapter | udinic

  10. Hello,

    i am trying to use AccountManager in an Activty under Application (not Service), but without sucess. I use an 4.3 emulator (Intel image). I can easly liist all accounts on the emulator (added via android interface) but when I want to create one an Error comes in:

    09-14 13:21:21.863: E/AndroidRuntime(3291): FATAL EXCEPTION: main
    09-14 13:21:21.863: E/AndroidRuntime(3291): java.lang.SecurityException: caller uid 10046 is different than the authenticator’s uid
    09-14 13:21:21.863: E/AndroidRuntime(3291): at android.os.Parcel.readException(Parcel.java:1431)
    09-14 13:21:21.863: E/AndroidRuntime(3291): at android.os.Parcel.readException(Parcel.java:1385)
    09-14 13:21:21.863: E/AndroidRuntime(3291): at android.accounts.IAccountManager$Stub$Proxy.addAccountExplicitly(IAccountManager.java:719)
    09-14 13:21:21.863: E/AndroidRuntime(3291): at android.accounts.AccountManager.addAccountExplicitly(AccountManager.java:612)

    My code snippets are:

    Login.java ->

    AccountManager accountmanager = AccountManager.get(this);

    Account userAccount = new Account(“Test”, “cg.activities”);

    if (accountmanager.addAccountExplicitly(userAccount, “pass”, null))
    System.out.println(“Added success”);
    else System.out.println(“Added failed”);

    res/authenticator.xml ->

    manifest ->

    I searched trouhg Google and StackOverflow, but without result. Tried it on 2.2 Android phone and the error is the same. Your app works on my phone. Drives me wild :S

  11. Hey Thanks for your great tutorial here. can you please explain more about server part of your app. here you said you use parse.com servers. I want to implement my own server. what is the approach for returning auth token?

  12. Simply desire to say your article is as amazing. The clarity to your publish is simply great and that i could suppose you are a professional
    on this subject. Well along with your permission let me to snatch your feed to keep updated with coming near
    near post. Thank you a million and please continue the gratifying work.

  13. Hey there!

    I am just curious if it is possible to use one and the same account for multiple apps. I am able to request account information from a different account, but is it possible to add Accounts to the same AccountManager from different apps?

    Similar to what google does with their Gmail account which is used for the mail app, hangout, g+,…

    I researched a while and am still not sure if this is possible and if its good practise. I would appreciate if you could give me some input.

    best regards,
    Mike

    • You can share the account type between apps if they all share the same signing signature.

      If you install 2 apps with the same account type, but signed with different keys, you’ll get a “SecurityException: caller uid XXXX is different than the authenticator’s uid” when trying to add an account from the second app.

  14. Thanks a million……. I was here to implement sync adapter and I get to know about this post. This post is really amazing. Now I am really interested to implement it in my application.

    You’ve used the parse.com servers, the problem is I want to implement is on my own server.

    Could you please upload some server side code? Some php code?

    It would be really really big help for me, and I will be really thankful to you for this favor!

    Well worked bro. Keep this stuff coming…. We love you!

    Best Wishes!

    • Hey

      I didn’t write any server code for this example, and a server code will be different from one implementation to another. It can also be done in many different languages/platforms.

      I suggest you search the internet from some “inspirations” and then implement your own.

  15. Pingback: CopyQuery | Question & Answer Tool for your Technical Queries

  16. Pingback: Android AccountManager permission for a single custom account type | BlogoSfera

  17. It is the first day I do anything related to Android,
    The first thing to start with is authentication stuff,
    Thanks for this full covered workflow!

  18. Thank you for the full explanation!
    I would like to write my own authenticator to use between all my related apps.
    I can’t get it to work with more that one app.
    When I use your sample code, only the first installed app opens the authenticatorActivity (By clicking the “addAccount” button) and the second app does nothing when clicking this button.
    I read others commenting on the same thing. Can you please explain why? I really need this to work for me :)
    Thank you!

    • Using the same authenticator will require you to use a library project for the authenticator, and linking to it from any app that you wish using it.

      Regarding your problem, have you checked the logs to see if there’s any error?

      As I wrote on “Random stuff you may want to know” section 2, the first app to be installed will register its authenticator. Meaning, other apps needs to be signed with the same signing key in order for them to access the authentication data the first app saved.

      • Hi, This is what I did- The authenticator is in a library and the two apps (Signed the same) are using it.
        When I am checking your example its the same- Only the first installed app response to addAccount().

        This is what I get in the log:
        10-22 11:39:35.437: D/udinic(31466): UdinicAuthenticator> addAccount
        10-22 11:39:35.707: D/dalvikvm(31466): JDWP invocation returning with exceptObj=0x41d8f138 (Ljava/lang/NullPointerException;)10-22 11:39:35.737: D/dalvikvm(31466): JDWP invocation returning with exceptObj=0x41d8f6b8 (Ljava/lang/ClassNotFoundException;)

        I understand that the first installed app is registering the authenticator but it looks like the second app can’t reach it. Any suggestions?….

  19. Sorry but your uploaded project is slightly unclear. I cannot get the app to work on my device. Do I have to create an entire new project to test example 1 and 2. When I try and runt the main.java files in Eclipse the AuthenticatorActivity.apk is installed but nothing is launched. This is not surprising as the manifest does not include a launcher activity.

    How are you supposed to test your example apps?

  20. Hi,

    Thanks for sharing your experience with the Android AccountManager. Could you please add a link to the Article in the Android documentation where you took the picture of the getAuthToken() method from? I couldn’t find it by myself.

    Thanks!

  21. Hi

    First of all let me comment you for a very great tutorial you have put up it is very insightful and helpful. However I have a question and I think you could probably help. I want to do something that will allow the user to create account and the sign in once in an environment where there is a network communication and then stores and encrypt the user’s authentication details on the device for future sign in in the event that the user is in a place where there is no network communication. Can you please advice on how this can be done. Thanks

  22. Hi,

    great tutorial. its working like a charm.

    now i want to know if you could give me a lead.
    i will have a couple of applications, all using one type of authentication.
    What i want to do is check if the account exists in any of the applications, and if there is no account created, call the authentication module for create one.

    i almost accomplish that but i dont know why android are asking for modification permissions. in both applications. is this correct or im doing something wrong?

    regards.

    • It’s not quite clear what you are trying to do.

      When do you check that? When the app first launches? In that case just try to get an auth token and the authenticator will start the log-in activity for you in case there are no credentials stored already.

      Please clarify your question.

  23. Hi Udinic,
    Its Very very great Tutorial. Really it simplified my understanding about AccountAuthenticator. But still I have one problem regarding following :
    1. How to Check existing account validity if the user is already logged in and already that account exists. Your help will be appreciable .
    Regards.

    • Well..you can use the account’s credentials and see that they still valid against the server. If they are not – just invalidate them using invalidateAuthToken, and next the app will try to use them – it’ll ask the user for new credentials.

  24. Pingback: How to implement user login with google, facebook or twiter in android app?CopyQuery CopyQuery | Question & Answer Tool for your Technical Queries,CopyQuery, ejjuit, query, copyquery, copyquery.com, android doubt, ios question, sql query, sqlite query

  25. Thanks for the article, it was very helpful. One thing that is worth noting: you’ll need to add android:exported=”true” to the login and register activities in order to access them from the second application. Without that, you’ll get a securityexception from the second app complaining that the activity is not exported.

    • I have just implemented Android Authenticator using this blog post and I did not store the password at all. You do not have to put actual password there. I think it is optional.

      In this example, when the user token is not valid, it uses that stored password and re-authenticate immediately. If you do not store the password, you just have to ask for the password again.

  26. Hi,

    Thanks for the great tutorial. One thing I wanted to mention:

    I think it would be better if you put the explanation of “sServerAuthenticate” and “authTokenType” before the creating activity part. Because in the getAuthToken() method, both of them are used and it was a little confusing (at least for me) not having any explanation about them right after that part.

  27. Hi,

    Thanks for the great tutorial, clears up all the things, but maybe you can help with a related question.

    I need to create a client app for an OAuth2 API using a Bearer token for authentication. At the time of obtaining the token, I receive the expiry timestamp for it, but I am unclear about where to store and how to utilize it. Problem is, if I don’t want to have unnecessary trips to the server, the app would realize that the Bearer had become invalid only after it receives a HTTP 401 error from the server.

    – Should every network request in my code have a retry mechanism in case the bearer token has become invalid in meantime?
    – Can SyncAdapter somehow help with this?
    – As I am new to Android development, is there maybe anything else?

    Thanks!

    • The correct way to handle invalid auth tokens is using the invalidateAuthToken() whenever you get a 401 from server.

      Doing that, will cause the authenticator to authenticate the user again, instead of returning the auth token again.

  28. Hi,

    I want to a Switch as you have prefs.xml. I should be able to read the value from the application, who is responsible for account and not from the settings.

  29. Problem solved, I didn’t know that account type must be the package name ! I have two questions (for now) to ask : When an auth token is no longer valid (time elapsed) do I need to “refresh” it “manually” ? How to automatically detect password change ?

  30. Thanks Udinic for this great tutorial. Browsing the code on Github i saw a comment on the AccountAuthenticatorActivity where you said that ” There can only be one AuthenticatorActivity ” from witch you started a second activity (sign up activity) and i was wondering why. Can’t you just start another AuthenticatorActivity from the main activity just for the sign up?

    • Activities who are extending from “AuthenticatorActivity” has special properties. Starting a new activity like this has implications of information retrieval and status codes code returned to the Authenticator itself.

      Every AuthenticatorActivity is linked to the account authenticator and returns information it needs once the user has submitted data in it (such as username/password). You can take a look at the AuthenticatorActivity source code and learn more about its properties and the things it does.

      Because it’s a special type of activity, you cannot just start a new AuthenticatorActivity.

  31. Where do you check if the token has expired? I have a server which gives me the timestamp and expiry time. I want to store both these fields into account manager and check if the token has expired. I am not sure – how are you handling the token expiry check?

  32. Hi
    Nice tutorial. But i dont want to use oAuth. I have an own login screen and authenticate with ldap. Can you tell me how to create oauth and session id for this case

  33. Pingback: Android AccountManager no account after restarting applicationCopyQuery CopyQuery | Question & Answer Tool for your Technical Queries,CopyQuery, ejjuit, query, copyquery, copyquery.com, android doubt, ios question, sql query, sqlite query, nodejsquery

  34. Has anyone tried accessing the Authenticator from an app which is signed by a 3rd party ? Using the sample code, out of the box, I keep getting “W/Binder(461): java.lang.SecurityException: Activity to be started with KEY_INTENT must share Authenticator’s signatures”

  35. i whould like to sync contact like what’sapp .but i confuse in server side concept because i download whatsapp at first time and its show all contact which have already what’s app user please help me how to apply this concept in my application. do you have any idea and reference pls suggest me.

  36. Hi Udinic,
    I have two applications which are signed by the same signature. In order to get/set user data the AccountManager documentation specify that both apps should have the same sharedUserID in the manifest file but when i do that i cannot seem to update the applications due to different sharedUserID. the other weird thing is that when i’m not using sharedUserID at all everything works fine as opposed to the documentation.
    Will it be safe to do it without the sharedUserID?

    • You need to have the same shared user id for that to work. Try to uninstall and reinstall your apps again after you set their sharedUserId to be the same.

  37. After I initially left a comment I appear to have clicked on the -Notify me when new comments are added- checkbox
    and now every time a comment is added I
    get four emails with the same comment. Perhaps there is an easy
    method you are able to remove me from that service? Thanks a lot!

  38. How does this approach work when using account types for 3rd parties? For example, lets say that I want to authenticate against LinkedIn and the LinkedIn app isn’t installed, so there is currently no LinkedIn account available. I can create the authentication logic the way you have shown in this tutorial, but then wouldn’t I have to set the icon, title, description, etc. for the LinkedIn account? Then if the user eventually does install the LinkedIn app, there would be 2 LinkedIn accounts – one official, one unofficial. Any thoughts on this situation? Thanks.

    • Well..if you want to use the other app’s logged-in account, you need it to be installed first. If you want to create *your own* account that connects to their server and retrieve an auth-token, you can do that too, but it’ll need to be a different account type than the one they are using, otherwise – installing their app will lead to a security exception.

      Linkedin is not a good example, since I know they don’t use an authenticator (at least they didn’t 6 months ago), but let’s take Dropbox as an example. If you will create an account type with exactly the same name as they did, there will be a problem installing Dropbox after your app, since they both need to share the same account type and both have different signing keys, which is a security problem.

      You can try that and see for yourself what happens in such situation.

  39. Pingback: Android: How to implement an account login system? | questions android

  40. Well done for the great work and the comprehensive tutorial. Simple, relevant and functional; as all things should be.

  41. hello udinic i cant sync my application with contact…i required to syncr contac with my apps…like whatsup install in my phone i get in all contact which one use ….so do this type of synchronization pls help me its a very important for me…

  42. Hi Udinic,
    Really thanks for this nice tutorial.
    I am able to run it.
    But I see my app in accounts only when I add it manually.
    How can I achieve it without adding manually, as other app comes.

    Thanks in advance.

  43. Grea site. A lot of ueful information here. I’m sending iit to a few buddies ans additionally sharing in delicious.
    And of course, thasnks on your effort!

  44. What’s Taking place i am new to this, I stumbled upon this I’ve found It positively
    helpful and it has aided me out loads. I’m hoping too
    give a contribution & aaid other customers lile its aided me.
    Good job.

  45. Hey I know this is off topic but I was wondering if you knew of any widgets I could add to my
    blog that automatically tweet my newest twitter updates.
    I’ve been looking for a plug-in like this for quite some time and was hoping maybe
    you would have some experience with something like this.
    Please let me know if you run into anything. I truly enjoy reading your blog and I look forward to your
    new updates.

  46. Hey, thanks for this great tutorial. I hope you’re still looking at comments because I’ve been fighting with this for a couple days now.

    I’m using getAuthTokenByFeatures() as it’s supposed to encapsulate all the logic of using an account if it’s already there (and there’s only 1), or showing a picker to the user if there’s more than 1, or creating the account if there are none. I’ve found that last statement a little misleading as I still had to do the addAccountExplicitly() in my AccountAuthenticatorActivity. However, once I did that, it worked… mostly.

    If AccountManager has a token cached (and thus doesn’t even need to call my authenticator), then my callback I specify on the getAuthTokenByFeatures() gets called with the AccountManagerFuture. However, if it DOESN’T have a token cached (or I need to create a new account, both behave the same), my callback NEVER gets called. The account is added in AccountManager, and next time I come in it’ll work because the token is cached and it doesn’t call my authenticator. But any time my authenticator is in the picture, the callback isn’t called.

    This is the code I have at the end of my authenticator’s getAuthToken():

    // Didn’t find a valid token. Return a response that’ll show the login screen.
    Intent intent = new Intent(mContext, LoginActivity.class);
    intent.putExtra(Constants.KEY_AUTH_TOKEN_TYPE, authTokenType);
    intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);

    Bundle result = new Bundle();
    result.putParcelable(AccountManager.KEY_INTENT, intent);
    return result;

    And this is the code I have in my AccountAuthenticatorActivity that should return the result:

    // Done. Tell the AccountManager what we got/created.
    Intent intent = new Intent();
    intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, mEmail);
    intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE, accountType);
    intent.putExtra(AccountManager.KEY_AUTHTOKEN, loginResult.getAuthToken());
    intent.putExtra(KEY_LOGIN_RESULT, loginResult);
    setAccountAuthenticatorResult(intent.getExtras());
    setResult(RESULT_OK, intent);
    finish();

  47. Hy bro !
    i am new in android. How i can do drive api authorization for android application.?
    I saw google drive authorize tutorials but no thing find help full.
    plz help me I will be very thank full to you.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s