I've seen AccountManager in the Android SDK and that it is used for storing account information. Thus, I cannot find any general discussion of what it is intended for. Does anyone know of any helpful discussions of what the intention behind AccountManager is and what it buys you? Any opinions of what type of Accounts this is suitable for? Would this be where you'd put your user's account information for a general web service?
This question is a bit old, but I think it is still of good interest.
AccountManager, SyncAdapter and ContentProvidergo together.
You cannot have a SyncAdapter without an Account in the AccountManager.
You cannot have a SyncAdapterwithout a ContentProvider.
But you can:
use the ContentProvider without the others.
use the AccountManager without the others (but you cannot use an AccountManager without a SyncAdapter before Android 2.2 / Froyo API 8)
With AccountManager / SyncAdapter / ContentProvider:
AccountManager gives users a central point (Settings > Accounts) to define their credentials
Android decides when synchronization can be done via SyncAdapter. This can be good to optimize battery (no sync is done when network is down, for instance)
ContentProvider is a convenient way to share data across applications
Note: there are other methods of inter-process communication on Android.
ContentProvider schedules the database access in a background thread The AsyncQueryHanlder helps to query the ContentProvider in a background thread, preventing Application Not Responsive (ANR) errors while not requiring you to explicitly handle threading.
ContentProvider ties into ContentResolver's observer: this means it is easy to notify views when content is changed
Bottom line: the framework AccountManager / SyncAdapter / ContentProvider helps if you want to synchronize data from a web resource. Fake/Dumb implementations are required on API 7. Also
If you only want to store data, you should consider a simpler mechanism for data storage
If you only need to fetch an only resource, you can use an AsyncTaskLoader
If you want to load images asynchronously, you can use specialized libraries like Square Picasso
If you only want to execute some code at a given time, you can consider a Service / Alarm
only available from API >= 7 (this doesn't matter anymore)
Finally, if you use a SyncAdapter, seriously consider Firebase Cloud Messaging (previously Google Cloud Messaging) aka "push notifications" to have fresher updates and optimized battery usage.
The AccountManager class is integrated with your phone accounts. So if you follow all the guides and get it working correctly you'll see your accounts under the menu "Settings->accounts and sync". From there you can customize them or even delete them. Furthermore the accountManager has a cache of the authentication tickets for your accounts.
This can be used also if you don't plan to synchronize your account (as far as I know).
If you don't want your accounts to appear under that menu you shouldn't use the AccountManager and store the accounts data elsewhere (maybe in the shared preferences) http://developer.android.com/guide/topics/data/data-storage.html
From http://www.c99.org/2010/01/23/writing-an-android-sync-provider-part-1/:
The first piece of the puzzle is
called an Account Authenticator, which
defines how the user’s account will
appear in the “Accounts & Sync”
settings. Implementing an Account
Authenticator requires 3 pieces: a
service that returns a subclass of
AbstractAccountAuthenticator from the
onBind method, an activity to prompt
the user to enter their credentials,
and an xml file describing how your
account should look when displayed to
the user. You’ll also need to add the
android.permission.AUTHENTICATE_ACCOUNTS
permission to your
AndroidManifest.xml.
The AccountManager is good for the following reasons:
First is to store multiple account names with different levels of access to the app’s features under a single account type. For example, in a video streaming app, one may have two account names: one with demo access to a limited number of videos and the other with full-month access to all videos. This is not the main reason for using Accounts, however, since you can easily manage that in your app without the need for this fancy-looking Accounts thing… .
The other advantage of using Accounts is to get rid of the traditional authorization with username and password each time an authorized feature is requested by the user, because the authentication takes place in the background and the user is asked for their password only in certain condition, which I will get to it later.
Using the Accounts feature in android also removes the need for defining one’s own account type. You have probably come across the apps using Google accounts for authorization, which saves the hassle of making a new account and remembering its credentials for the user.
Accounts can be added independently through Settings → Accounts
Cross-platform user authorization can be easily managed using Accounts. For example, the client can access protected material at the same time in their android device and PC without the need for recurrent logins.
From the security point of view, using the same password in every request to the server allows for possible eavesdropping in non-secure connections. Password encryption is not sufficient here to prevent password theft.
Finally, an important reason for using the Accounts feature in android is to separate the two parties involved in any business dependent on Accounts, so called authenticator and resource owner, without compromising the client (user)’s credentials. The terms may seem rather vague, but don’t give up until you read the following paragraph … 😉
Let me elaborate on the latter with an example of a video streaming app. Company A is the holder of a video streaming business in contract with Company B to provide its certain members with premium streaming services. Company B employs a username and password method for recognizing its user. For Company A to recognize the premium members of B, one way would be to get the list of them from B and utilize similar username/password matching mechanism. This way, the authenticator and resource owner are the same (Company A). Apart from the users obligation to remember a second password, it is very likely that they set the same password as their Company B’s profile for using the services from A. This is obviously not favorable.
To allay the above shortcomings, OAuth was introduced. As an open standard for authorization, in the example above, OAuth demands that the authorization be done by Company B (authenticator) by issuing some token called Access Token for the eligible users (third party) and then providing Company A (resource owner) with the token. So no token means no eligibility.
I have elaborated more on this and more on AccountManager on my website here.
Related
I'm trying to work out the best solution for a particular situation I'm in, and am having trouble working out the best option. It's a tricky setup, so might be a fun challenge for you Android experts! Here's my situation:
We have two Android apps already on the Play Store, and are working on another right now.
The two released apps are signed with the same keystore, but do not currently have a sharedUserId set in their manifest files.
The two released apps store a user's oAuth token in SharedPrefs, some product/content data in an SQLite DB, and some audio/video content in external storage (using getExternalFilesDir).
The apps are all separate oAuth clients/applications of our server (i.e. they all use different client ID and secret keys).
Our server is setup to only allow one oAuth token per oAuth application (i.e. Android app). e.g. if a user logs in to app A on one device, then logs into app A on another device, the first device's token will be invalidated and the app will receive a 401.
We've successfully implemented a single sign-on system on iOS by enabling shared keychain between the apps. If an app detects that another app in the group has a valid oAuth token, it can send that to our server and exchange it for a valid token for that app.
In the iOS version, we wanted to ensure that the apps didn't need to know about the existence of the other apps using hardcoded values per-app (e.g. if we release a new app in the future, other apps don't need to be updated to share/receive tokens with it), so we created an entry in the keychain containing an array of bundle IDs that had valid tokens, that all apps could access. When an app successfully logs in or exchanges a token, they add their own bundle ID to that array. Any newly installed app could find a bundle ID from that array, and use that it as a key for loading the token details for that app, which it would then exchange for its own fresh token.
We want the token exchange to be automatic and not require input from the user.
I hope that all makes sense!!! Please let me know if not.
I'm now trying to work out the best method for storing oAuth tokens (plus some additional data such as email address to go with it) on Android so that other apps owned by our account can access them in order to exchange for a fresh token.
I've looked into using the following, but am unsure of the best route:
SharedPreferences along with sharedUserId
AccountManager (https://developer.android.com/reference/android/accounts/AccountManager.html)
Android Keychain (https://developer.android.com/reference/android/security/KeyChain.html)
ContentProviders
The problem with option 1. seems to be that setting the sharedUserId after first release will lose access to all of the data (see http://java-hamster.blogspot.jp/2010/05/androids-shareduserid.html). This is not a nice thing for our users.
Option 2. (AccountManager) could be a good option, but if we want to store the tokens separately (per-app), but want any other apps we make to access their tokens, I'm not sure how we'd do that.
Option 3... is it possible to do what we need with Keychain?
If I understand correctly, option 4 would need each app to have its own ContentProvider? I'm not sure how that would work for our requirements.
If anyone has gone through this kind of situation and could share some insights and recommendations, I'd really appreciate it!
ContentProvider is probably your best best. I won't be able to provide the whole code for you to do this, but this is generally how I see it working:
Each app creates a content provider that exposes their own API token;
Each app tries to acquire and query (sequentially until successful) all the other content providers before requesting a login;
If app X is able to acquire and retrieve the token from app Y (via Y's content provider), then store it in app X and use it;
Side notes:
This is very sensitive information, so you should enforce security. Your content providers should only be accessed by other apps signed with the same key, they should have only read permissions and you should create your own custom permission as well.
The content provider does not need to access an sqlite database. It can access whatever your using to store the token (which I hope is stored in a secure way, but I'll leave that to your own judgment)
Useful links:
How to create a custom content provider
How to secure your content provider
Example of content provider that retrieves data from shared preferences;
AccountManager is meant to solve the exact problem that your are commenting. Here is a good tutorial to work with it:
http://blog.udinic.com/2013/04/24/write-your-own-android-authenticator/
Just be sure that you sign all your apps with the same keystore, because this is the only thing that might complicate things (a lot).
Using preferences will lead you into a problem as all that you store in the main thread is not guaranteed to be there in a Service (like a SyncAdapter). There used to be a trick for this in the form of flag (MULTI_SERVICE) but was deprecated in api 23.
ContentProvider is of course possible (its too generic) but AccountManager will help you to cover the corner cases related from refreshing tokens and other interesting stuff.
How can you uniquely identify a user who has installed your app so that:
You will know it is them if they delete and reinstall your app;
You will know it is them if they install your app on a second device they intend to use simultaneously?
Just as an example, I see that the Netflix app will automatically link to your desktop account without any user interaction. I'm guessing that they use accountManager.getAccounts() or similar method, because they also require the GET_ACCOUNTS permission. But of course that permission is marked as Protection level: dangerous. Is there any technique to do this that is less invasive or potentially alarming?
The key to answering this is to be both simple (for the user) and minimally invasive. Android provides heaps of ways to identify users and many of those ways involve piercing a user's privacy, and if that is the only way, I will do what I do now (optional email registration). I just want a way for my app to know if a user already is registered in my system across installs without having to interview the user (username/password, email address, third-party OAuth, etc).
My main reasons are:
I don't want support requests from users who orphaned their content after a reinstall; and
I don't want to host lots of orphaned content.
Have a look at Firebase Authentication. It's quite seamless and does not require much effort to incorporate. Also it does not feel intrusive or cumbersome to the end user.
Here is a video tutorial by Google.
EDIT:
In case your users are sure to have a cellular device with a phone number, you can use AccountKit. It is also what they call OTA (One Time Authentication). AccountKit uses just the users phone number to verify and validate users.
EDIT:
Firebase Authentication now features 'Phone Verification' which is similar to AccountKit mentioned above. Both are good services. However, Firebase phone verification lets you make your own UI from scratch (which means a lot better control than AccountKit). Also, if you don't want to make your UI, you can always use FirebaseUI
i have implemented something that seems little similar to your thing by push notification , i can get error if user uninstalled my app(and from the registration id i get the user) , and if he re installed he obtain a new registration id , and try to get the user UUID for different devices
I think the simplest way would be using UUID and storing the hash on sharedPreferences. You should generate the UUID as earlier as possible in your app.
sharedPrefs = context.getSharedPreferences(APP_SHARED_PREFS,Activity.MODE_PRIVATE);
if (sharedPrefs.getString("YOUR-KEY-TO-THE-UUID") == null || "".equals(sharedPrefs.getString("YOUR-KEY-TO-THE-UUID"))){
prefsEditor = sharedPrefs.edit();
prefsEditor.putString("YOUR-KEY-TO-THE-UUID", UUID.randomUUID().toString());
prefsEditor.commit();
}
I think that the best way would be implementing login with Google or Facebook. This is quite seamless for users, safe enough (as Google and Facebook considered trusted), you do not need to implement your email registration and you will have identity across devices.
If your app is Android only and you'd like to provide identity without any account creation for the user, I believe using Google Account name/id is the best choice (Accessing Google Account Id /username via Android) since you have to use Google Account on Android phone (unless you root it, delete Google Play Services etc).
If you'd like to only address the first point of your question (identify after reinstall) there's a Device Id -Secure.getString(getContext().getContentResolver(), Secure.ANDROID_ID);
though it's not 100% reliable (f.e Factory Reset resets this value)
The standard for achieving this sort of functionality is through the use of JSON web tokens (JWT) in conjunction with standard restful api traffic.
Assuming your android application interacts with a RESTful api for all crudlike operations and business logic, then using a JWT as an authentication identifier to your api can work quite well. You can embed information in each JWT allowing you to identify whatever you like (the user id in the database, the device id of whereve the user logged in from, etc). A JWT is essentially a datastructure allowing you to store information to be used by the API.
Some basics for how this works:
Getting the JWT into the app: A user logs in to the application using their username/password. The
api then returns an encrypted JWT to be used by the client for all future requests. Don't try to do
the encryption yourself. Any language that can handle serving an api
will have libraries for this.
Using information in the JWT: The JWT is itself a datastructure. For example, it might look like this:
{
user_id: 1,
device_id: 44215,
device_os: android,
}
Your api will decrypt the JWT when it is supplied for
authentication via the request header, and then have that information available in the
context of the session.
If you provide the language used by your api then I might be able to recommend a library.
I will conclude by referring to the final requirement you submitted which states essentially that you do not want to have to interview the user across installs. If I understand your meaning, that you want a user to be able to simply install the application and begin using it without supplying authentication credentials, then there is no way to achieve that securely. You might be able to come up with a hackish way to get it to work, but it will be fundamentally insecure.
AccountManager vs AIDL vs ContentProvider are use to share data with other app. but which is the better for sharing authentication details with other app like google does.
I prefer AccountManager .
This class provides access to a centralized registry of the user's
online accounts. The user enters credentials (username and password)
once per account, granting applications access to online resources
with "one-click" approval.
Different online services have different ways of handling accounts and
authentication, so the account manager uses pluggable authenticator
modules for different account types. Authenticators (which may be
written by third parties) handle the actual details of validating
account credentials and storing account information. For example,
Google, Facebook, and Microsoft Exchange each have their own
authenticator.
The Android Account Manager is basically an API available to Android developers that makes use of the OAuth protocol. Developers have to jump through some hoops to get their app to display in Accounts & Sync, but the first step is adding the AUTHENTICATE_ACCOUNTS permission to the manifest file for the app.
Content Provider is the mechanism used to expose many of a device's data resources for retrieval and update: Contacts, media store, bookmarks, phone-call log, and so on. It’s hard to find an interesting Android app that doesn’t either use or implement (or both) a Content Provider.
Please read
What should I use Android AccountManager for ?
When to use a Content Provider
When to use an aidl based service?
Let's say I have this application developed for Android which needs to use a Facebook (or Twitter or Google or all of them) based authentication so it can access this private API I've developed with nodejs' Express for example (could be any other platform too). I've read this answer here that gave me a hint on how to associate my authentication model with my user model (and another one here that made me realize those two parts are different), Facebook authenticates and I use some information they provide to create an "identity" for this user, but what exactly is this information that will create a link between the user and the identity? no abstract terms please, do I need to use and send either the access token or the Facebook user id? or would I just send the access token and let the server get the user id?
Regarding new requests after this user has been authenticated, I've read about API keys of some sort, which are basically some random strings that I should add to my identities (or users? this part confuses me) entities, and they should be securely stored in the mobile device as a mechanism to authenticate further requests, but how do I securely get this random string to the device in the first place? am I misunderstanding the way API keys work? are Facebook authentication and API keys mutually exclusive? if so, what would I use for further requests just using a provider for my authentication? it seems illogical to pass the access code in every request, even more so passing the user id.
The focus of this question is for me model a solid strategy for managing this authentication-user-identity behavior, would love any insights on how has this been done before since the material I've found in SO and the web has been very lacking, often referring just to server side implementations or just authentication answers, not addressing the issue of further requests.
The Facebook/User ID is there to identify the (returning) User. Keep in mind that you only get an "App Scoped ID", not the "real" ID - it will be unique in the App, but different in another one. See changelog: https://developers.facebook.com/docs/apps/changelog
Access Tokens are there to make calls to the Graph API. There are 3 different Tokens (App Token, User Token, Page Token), you can read more about them in those articles:
https://developers.facebook.com/docs/facebook-login/access-tokens/
http://www.devils-heaven.com/facebook-access-tokens/
You can store Access Tokens for later, but in most cases you don´t need to store them - only if you need to access the API while the User is not using your App.
In general, App Tokens can be used to request public stuff and to change App settings. User Tokens can be used to request (or post) User stuff and Page Tokens can be used to request insights of a Facebook Page and other things.
If you want to deal with Access Tokens on your own, make sure to activate appsecret_proof in the settings. I suggest reading this article about securing API calls: https://developers.facebook.com/docs/graph-api/securing-requests
I've seen AccountManager in the Android SDK and that it is used for storing account information. Thus, I cannot find any general discussion of what it is intended for. Does anyone know of any helpful discussions of what the intention behind AccountManager is and what it buys you? Any opinions of what type of Accounts this is suitable for? Would this be where you'd put your user's account information for a general web service?
This question is a bit old, but I think it is still of good interest.
AccountManager, SyncAdapter and ContentProvidergo together.
You cannot have a SyncAdapter without an Account in the AccountManager.
You cannot have a SyncAdapterwithout a ContentProvider.
But you can:
use the ContentProvider without the others.
use the AccountManager without the others (but you cannot use an AccountManager without a SyncAdapter before Android 2.2 / Froyo API 8)
With AccountManager / SyncAdapter / ContentProvider:
AccountManager gives users a central point (Settings > Accounts) to define their credentials
Android decides when synchronization can be done via SyncAdapter. This can be good to optimize battery (no sync is done when network is down, for instance)
ContentProvider is a convenient way to share data across applications
Note: there are other methods of inter-process communication on Android.
ContentProvider schedules the database access in a background thread The AsyncQueryHanlder helps to query the ContentProvider in a background thread, preventing Application Not Responsive (ANR) errors while not requiring you to explicitly handle threading.
ContentProvider ties into ContentResolver's observer: this means it is easy to notify views when content is changed
Bottom line: the framework AccountManager / SyncAdapter / ContentProvider helps if you want to synchronize data from a web resource. Fake/Dumb implementations are required on API 7. Also
If you only want to store data, you should consider a simpler mechanism for data storage
If you only need to fetch an only resource, you can use an AsyncTaskLoader
If you want to load images asynchronously, you can use specialized libraries like Square Picasso
If you only want to execute some code at a given time, you can consider a Service / Alarm
only available from API >= 7 (this doesn't matter anymore)
Finally, if you use a SyncAdapter, seriously consider Firebase Cloud Messaging (previously Google Cloud Messaging) aka "push notifications" to have fresher updates and optimized battery usage.
The AccountManager class is integrated with your phone accounts. So if you follow all the guides and get it working correctly you'll see your accounts under the menu "Settings->accounts and sync". From there you can customize them or even delete them. Furthermore the accountManager has a cache of the authentication tickets for your accounts.
This can be used also if you don't plan to synchronize your account (as far as I know).
If you don't want your accounts to appear under that menu you shouldn't use the AccountManager and store the accounts data elsewhere (maybe in the shared preferences) http://developer.android.com/guide/topics/data/data-storage.html
From http://www.c99.org/2010/01/23/writing-an-android-sync-provider-part-1/:
The first piece of the puzzle is
called an Account Authenticator, which
defines how the user’s account will
appear in the “Accounts & Sync”
settings. Implementing an Account
Authenticator requires 3 pieces: a
service that returns a subclass of
AbstractAccountAuthenticator from the
onBind method, an activity to prompt
the user to enter their credentials,
and an xml file describing how your
account should look when displayed to
the user. You’ll also need to add the
android.permission.AUTHENTICATE_ACCOUNTS
permission to your
AndroidManifest.xml.
The AccountManager is good for the following reasons:
First is to store multiple account names with different levels of access to the app’s features under a single account type. For example, in a video streaming app, one may have two account names: one with demo access to a limited number of videos and the other with full-month access to all videos. This is not the main reason for using Accounts, however, since you can easily manage that in your app without the need for this fancy-looking Accounts thing… .
The other advantage of using Accounts is to get rid of the traditional authorization with username and password each time an authorized feature is requested by the user, because the authentication takes place in the background and the user is asked for their password only in certain condition, which I will get to it later.
Using the Accounts feature in android also removes the need for defining one’s own account type. You have probably come across the apps using Google accounts for authorization, which saves the hassle of making a new account and remembering its credentials for the user.
Accounts can be added independently through Settings → Accounts
Cross-platform user authorization can be easily managed using Accounts. For example, the client can access protected material at the same time in their android device and PC without the need for recurrent logins.
From the security point of view, using the same password in every request to the server allows for possible eavesdropping in non-secure connections. Password encryption is not sufficient here to prevent password theft.
Finally, an important reason for using the Accounts feature in android is to separate the two parties involved in any business dependent on Accounts, so called authenticator and resource owner, without compromising the client (user)’s credentials. The terms may seem rather vague, but don’t give up until you read the following paragraph … 😉
Let me elaborate on the latter with an example of a video streaming app. Company A is the holder of a video streaming business in contract with Company B to provide its certain members with premium streaming services. Company B employs a username and password method for recognizing its user. For Company A to recognize the premium members of B, one way would be to get the list of them from B and utilize similar username/password matching mechanism. This way, the authenticator and resource owner are the same (Company A). Apart from the users obligation to remember a second password, it is very likely that they set the same password as their Company B’s profile for using the services from A. This is obviously not favorable.
To allay the above shortcomings, OAuth was introduced. As an open standard for authorization, in the example above, OAuth demands that the authorization be done by Company B (authenticator) by issuing some token called Access Token for the eligible users (third party) and then providing Company A (resource owner) with the token. So no token means no eligibility.
I have elaborated more on this and more on AccountManager on my website here.