Clarification of OAUTH 2 Grant Types - android

Been doing some reading regarding OAUTH2.
So...
Authorisation Code Grant: Is for users who want to access MY application/API through a third party application. Example: A user through Flicker wants to access MY photo printing API. In this case Flicker will do all the redirection and the OAUTH2 flow with MY servers. Access token is provided and 3rd party application can use MY API as needed. The application developer will need to register to get the client id and client secret.
Implicit: Same as above except the mobile/app doesn't have a back end server to safekeep the client secret. The mobile app will handle redirect and OAUTH2 flow. Access token is provided and 3rd party application can use MY API as needed. Refresh token not supported. The application developer will need to register to get the client id.
Resource Owner Password Credentials Grant: In this case, this is MY mobile/web app that I distribute to my users through the typical iTunes/Play stores. The users strictly use MY app to do their day to day stuff. MY mobile/web app will ask the user for Username/Password and post them to MY back end where it will authenticate and then provide back the access token.
Client credentials grant: This case is used for application to do internal machine to machine stuff. I.e: MY App1 accessed MY App2, in the back end somewhere.
For now I do not foresee sharing my API with 3rd parties and my users will install MY app through iTunes/google play. I suppose that Password Credentials is good for me right now. Eventually if I want to open up my API to the rest of the world I will have to implement Authorisation Code Grant
As I searched around for this subject, I came across this link: https://alexbilbie.com/guide-to-oauth-2-grants/ which has a nice decision flow.

OAuth2 is used when you want to authorize/delegate access on your resources to a client (third party application).
There are at least 4 actors:
The authorization server
The client
The resource owner
The resource server
The application/API is the resource server. It stores and manages all resources of the resource owner.
The client is the party who want to access on those resources.
The authorization server is the server who authorize client to access on resources by issuing an access token.
Authorization Code Grant is designed for confidential clients (able to keep their credentials secured).
Implicit Grant is design for public client (not a confidential client) and especially for scripting language applications (JS...)
Resource Owner Password Credentials Grant is designed for any type of client but supposed that the client knows the password credentials of the resource onwer. In general this grant type is dedicated to trusted clients only.
Client Credentials Grant allows the client to access on its own resources (in this case the resource owner is the client).
The use of the Resource Owner Password Credentials Grant should be avoided, however it remains a good solution for legacy applications and if there is a trusted relationship between the client, the authorization server and the resource server.

Related

What prevents another app from stealing my Google OAuth client ID?

I created an Android app that uses AppAuth to authenticate with Google OAuth. In the Google Cloud Platform Console, I created an Android OAuth 2.0 client ID for my app and provided the app package name and signing-certificate fingerprint. Everything is working fine.
I wanted to verify that only my app can use that client ID. So I created a second app with a different package name and signed it with a different signing certificate. Using that same client ID, I'm still able to authenticate with Google and access APIs. I didn't think this should be the case. I was looking at the source code for AppAuth and it doesn't look like it ever uses the app signing or package name during the authentication flow. It uses PKCE of course, but I expected more to be happening.
So if I can steal my own client ID with little effort, what's to stop someone else from extracting my client ID from my APK and using it for authentication? The custom scheme I'm using for redirect URI is easy to figure out based on my package name. So the rouge app could configure AppAuth to use a similar redirect URI and capture the authorization result. And since PKCE is only used to verify the authorization request and code exchange come from the same place, a rouge app would be doing both so there's no real protection there either.
I could switch the client ID type to Web or Other, but that will require me to use a client secret, which is just as insecure if you embed it in an app.
Am I missing something or is Google OAuth working exactly as it was intended?
For client side Google OAuth 2, your Client ID does not really matter. The client performs the OAuth flow and the client receives the OAuth token. The magic is that the client must authorize Google. Anyone can steal your Client ID but they cannot do anything with it. As part of the OAuth lifecyle you should be validating OAuth tokens. Your backends should NOT be blindly accepting anything from a client - or anywhere not under your absolute control.
Your Client ID is not a secret and you can put that in the clear in your code.
It is the Client Secret which must remain secret. The Client Secret is not involved in client side authentication. The Client Secret is used on your backend servers.
I think that you are confusing the process. When the client application (your app, a web browser, etc.) authenticates with Google Accounts, your app is not being authorized. The client is being authorized. The client should use good judgement on which websites they visit (or apps) and use their Google logins with. The only thing that a client can do with their token is access their own data (Google Drive, Gmail, etc.). If your backend servers are accepting the client's OAuth token to manage access, then you are responsible for validating that token and its desired usage on your systems and who that token is authorized from.
A better choice is to perform authentication and authorization on the backend (your web server for example). Then you can implement the Google OAuth redirect to send the OAuth token to your servers. You are protected in that only authorized origins (your domain name for example) and authorized redirect URIs (an endpoint on your web server) can be involved in the authentication process. You then store the token in your client session, renew when necessary, add authorization scopes as required, etc.
I frequently use both methods (client side, server side) and both work well.
Thought I'd add a postscript here, related to the recommendations for mobile apps in Financial Grade APIs, to use Claimed HTTPS Schemes to receive login responses. This restricts use of the client id to apps with your digital signature.
For further info, see my blog posts, which describe code samples that anyone can run:
Android Code Sample
iOS Code Sample
Only native and one page apps don't have a client secret, so they have to switch to something else. Here the necessary protection is the redirect URL. For web hosted one page apps this is not a problem no matter how it is set up. They are hosted exactly on this redirect URL. For native apps another step has to be done. Android and iOS allow the use of "App-Claimed https URL Redirection". This ties an https URL directly to the app. These claimed URL redirections can be requested and must then be confirmed via signature on a specific address: https://developer.android.com/training/app-links/verify-site-associations.
With this method, in order to use a foreign client_id, the https redirect must be intercepted by the fake client (only rooted environment, which most phones are not).
With a lot of effort, a fraudster could run another frontend with the same client_id.
In a use case like this:
Using the API generates costs (e.g. own API)
Advertising on the frontend generates revenue
this is a reason to rethink the architecture.
In a use case described by you, this isn't a problem, as you don't own the API resource. The resource owner, which is the logged in GCP user, will have to pay for their GCP usage. On public clients, you cannot have the client itself authenticate with the authorization server (only the user is authenticated).

Android native app with Firebase Auth and MySQL backend

I am creating a native Android app which currently uses Firebase Auth to handle user authentication. I have a MySQL database behind a PHP site and I'm building a RESTful API to access those services. I would like users who are authorized to be able to access limited features and data.
In this scenario, what would be the approach to handling the permissions on the backend server? I'm new to Auth techniques such as OAuth etc, but I get the feeling that might be part of this solution, so feel free to talk to me like I'm an idiot. :)
[edit]
My backend has similar permissions to Facebook; such as content is visible as either private, friends or public.
Regards
It depends on your security design.
The easiest way is to have a role-based security - use OAuth2/OpenID Connect just for authentication (ask for an ID token, not access token). Then you must get a list of roles for an authenticated user. The roles could be part of the ID token or the API server could get them from another source (e.g. its database). If the role retrieval is an expensive operation, you could consider issuing your own token (JWT) containing all the info you need.
If you wanted to delegate just some of user's permissions to the mobile app, you could register the API scopes (permissions) to the OAuth2 server and the app could ask the user for some of them. As an example, if your application wants to access Google services on behalf of its user, the application asks for an access token with specific scopes (e.g. reading GMail inbox). But this is probably not what you want.
Edit:
If the objects you deal with have access rights defined on themselves (private, public, friends visible), then just get a user identity (ID token) from the OAuth2 server and check the permissions when someone requests such an object by your API. OAuth2 itself cannot help you with that.
And for your Android app, use the Authorization Code Grant Flow as described in the OAuth2 for native apps RFC.

OAuthorization through app or web api

My question is pretty straightforward but I am pretty sure it's just a lack of understanding on my part.
Background:
I have a prototype native android app as well as an asp.net Web API and I want to implement OAuthorization so that users can login through google+, Facebook, or Twitter.
Question:
What is the design pattern for this feature? I'm confused as to whether I implement OAuthorization through the mobile app or through the web API. It's probably a combination of both. I've read many blogs and tutorials but they fall short in helping me understand how these two aspects (app and web API) of my project would work together.
Thanks
In OAuth there are these players:
the Resources (for example your gmail contacts) this is not a player itself
the Owner of the resources (you're the owner of your gmail contacts)
The Authorization Server (where you login to gmail)
The Resource Server (gmail, which has the contacts).
The Client: an application which want to use the resources
Note that, in most occcasions, the resource server and the authorization server are the same server
OAuth allows you (the Owner of the resources: your gmail contatcs) to authorize a client (a third party app) to access the Resources (your gmail contacts) from the Resource server (gmail itself) on your behalf.
To do so, the typical flow is: you open the thrid party app (the client), and, when it needs to access your resource (the gmail contacts), it redirects you to the authorization server (gmail) and, apart form log in, if you wasn't logged in, the authorization server (gmail) informs you that your app (the client) is trying to access a resource (the contacts), so that you can approve or deny it.
If you approve it, gmail sends your application (throug an URL) a token which can be exchanged for a "bearer token". So, your app exchanges it, and receives the berare token, which can be presented to the resource server (gmail) to access the resource (contacts). From that moment on, the client (the third party application) will present the bearer token to the resource server and it will give it access to the resource (the contacts).
So, OAuth itself is not the best option for authentication. You can use it to authenticate by asking permission to get the basic profile info (name, perhaps email), and once you have access to that info you know who the user is. However, this simplistic implementation of Auth ad authentication server is not safe, so what you'll really use is OpenID, which is much safer. The flow is similar to he exaplined above, but it's standardized for different providers and safer.
The question is that you should use OpenID providers to delegate the authentication.
To see how to work with OAuth authentication, read this: Logging In Using External Sites in an ASP.NET Web Pages (Razor) Site and this: Code! MVC 5 App with Facebook, Twitter, LinkedIn and Google OAuth2 Sign-on
One option to use OpenID is dotnetopenauth.
NOTE: if you use OAuth, you need to register your application on the provider (Google, facebook...) so that you can use it. The OAuth authorization server must have a pre-configured list of clients (applications) with some configuration (for example the callback url, and client id and password) which will allow this clients (applications) to ask for permission to use them on behalf of the user (resource owner).
NOTE: you application can use OAuth to authorize itself, i.e. generate and check tokens, using OWIN middleware.
Once you understand the inner working of OAuth and OpenID, you can use any of the available libraries for different languages: from the openid.net libraries list.

Shouldn't Android AccountManager Store OAuth Tokens on a Per-App/UID Basis?

Android's AccountManager appears to fetch the same cached auth token for apps with different UIDs - is this secure? It does not seem compatible with OAuth2, since access tokens are not supposed to be shared between different clients.
Background/Context
I am building an Android app which uses OAuth2 for authentication/authorization of REST API requests to my server, which is an OAuth2 provider. Since the app is the "official" app (as opposed to a 3rd-party app), it is considered a trusted OAuth2 client, so I am using the resource owner password flow for obtaining an OAuth2 token: the user (the resource owner) enters his username/password into the app, which then sends its client ID and client secret along with the user credentials to my server's OAuth2 token endpoint in exchange for an access token that can be used to make API calls, as well as a long-lived refresh token used to get new access tokens when they expire. The rationale is that it is more secure to store the refresh token on the device than the user's password.
I am utilizing AccountManager for managing the account and associated access token on the device. Since I am providing my own OAuth2 provider, I have created my own custom account type by extending AbstractAccountAuthenticator and other required components, as explained in this Android Dev Guide and demonstrated in the SampleSyncAdapter sample project. I am able to successfully add accounts of my custom type from within my app and manage them from the "Accounts and sync" Android settings screen.
The Issue
However, I am concerned with the way the AccountManager caches and issues auth tokens - specifically, that the same auth token for a given account type and token type seems to be accessible by any app to which the user has granted access.
To obtain an auth token through the AccountManager, one must invoke AccountManager.getAuthToken(), passing, among other things, the Account instance for which to obtain the auth token and the desired authTokenType. If an auth token exists for the specified account and authTokenType, and if the user grants access (via the grant "Access Request" screen) to the app which has made the auth token request (in such cases where the requesting app's UID does not match the authenticator's UID), then the token is returned. In case my explanation is lacking, this helpful blog entry explains it very clearly. Based on that post, and after examining the source of AccountManager and AccountManagerService (an internal class which does the heavy lifting for AccountManager) for myself, it appears that only 1 auth token is stored per authTokenType/account combo.
So, it seems feasible that if a malicious app knew the account type and authTokenType(s) used by my authenticator, it could invoke AccountManager.getAuthToken() to obtain access my app's stored OAuth2 token, assuming that the user grants access to the malicious app.
To me, the problem is that AccountManager's default caching implementation is built on a paradigm on which, if we were to layer an OAuth2 authentication/authorization context, it would consider the phone/device to be a single OAuth2 client for a service/resource provider. Whereas, the paradigm that makes sense to me is that each app/UID should be considered as its own OAuth2 client. When my OAuth2 provider issues an access token, it is issuing an access token for that particular app which has sent the correct client ID and client secret, not all apps on the device. For instance, the user might have both my official app (call it app Client A), and a "licensed" third-party app which uses my API (call it app Client B) installed. For the official Client A, my OAuth2 provider may issue a "super" type/scope token which grants access to both public and private pieces of my API, whereas for the third-party Client B, my provider may issue a "restricted" type/scope token which only grants access to the the public API calls. It should not be possible for app Client B to obtain app Client A's access token, which the current AccountManager/AccountManagerService implementation seems to allow. For, even if the user grants authorization to Client B for Client A's super token, the fact remains that my OAuth2 provider only intended to grant that token to Client A.
Am I overlooking something here? Is my belief that auth tokens to should be issued on a per-app/UID basis (each app being a distinct client) rational/practical, or are auth-tokens-per-device (each device being a client) the standard/accepted practice?
Or is there some flaw in my understanding of the code/security restrictions around AccountManager/AccountManagerService, such that this vulnerability does not actually exist? I've tested the above Client A/Client B scenario with the AccountManager and my custom authenticator, and my test client app B, which has a different package scope and UID, was able to obtain the auth token that my server had issued for my test client app A by passing-in the same authTokenType (during which I was prompted with "Access Request" grant screen, which I approved since I'm a user and therefore clueless)...
Possible Solutions
a. "Secret" authTokenType
In order to obtain the auth token, the authTokenType must be known; should the authTokenType be treated as a type of client secret, such that a token issued for a given secret token type may be obtained by only those "authorized" client apps which know the secret token type? This does not seem very secure; on a rooted device, it would be possible to examine the auth_token_type column of authtokens table in the system's accounts database and examine authTokenType values that are stored with my tokens. Thus, the "secret" auth token types used across all installations of my app (and any authorized third-party apps used on the device) will have been exposed in one central location. At least with OAuth2 client IDs/secrets, even if they must be packaged with the app, they are spread out among different client apps, and some attempt may be made to obfuscate them (which is better than nothing) to help discourage those who would unpackage/decompile the app.
b. Custom Auth Tokens
According to the docs for AccountManager.KEY_CALLER_UID and AuthenticatorDescription.customTokens, and the AccountManagerService source code I referenced earlier, I should be able to specify that my custom account type uses "custom tokens" and spin my own token caching/storage implementation within my custom authenticator, wherein I can obtain the UID of the calling app in order store/fetch auth tokens on a per-UID basis. Basically, I would have an authtokens table like the default implementation, except there would be an added uid column so that tokens are uniquely indexed on U̲I̲D̲, a̲c̲c̲o̲u̲n̲t̲, and A̲u̲t̲h̲ ̲T̲o̲k̲e̲n̲ ̲T̲y̲p̲e̲ (as opposed to just a̲c̲c̲o̲u̲n̲t̲ and A̲u̲t̲h̲ ̲T̲o̲k̲e̲n̲ ̲T̲y̲p̲e̲). This seems like a more secure solution than using "secret" authTokenTypes, since that would involve using the same authTokenTypes across all installations of my app/authenticator, whereas UIDs vary from system-to-system, and cannot be easily spoofed. Aside from the joyful overhead of getting to write and manage my own token caching mechanism, what downsides are there to this approach in terms of security? Is it overkill? Am I really protecting anything, or am I missing something such that even with such an implementation in place, it would still be easy enough for one malicious app client to obtain another app client's auth token using the AccountManager and authTokenType(s) which are not guaranteed to be secret (assuming that said malicious app does not know the OAuth2 client secret, and therefore cannot directly get a fresh token but could only hope to get one that was already cached in the AccountManager on behalf of the authorized app client)?
c. Send client ID/secret w/ OAuth2 token
I could stick with the AccountManagerService's default token storage implementation and accept the possibility of unauthorized access to my app's auth token, but I could force API requests to always include the OAuth2 client ID and client secret, in addition to the access token, and verify server-side that the app is the authorized client for which the token was issued in the first place. However, I would like to avoid this because A) AFAIK, the OAuth2 spec does not require client authentication for protected resource requests - only the access token is required, and B) I would like to avoid the additional overhead of authenticating the client on each request.
This isn't possible in the general case (all the server gets is a series of messages in a protocol - the code that generated those messages can't be determined). --Michael
But the same could be said of the initial client authentication in the OAuth2 flow during which the client is first issued the access token. The only difference is that instead of authenticating on just the token request, requests for protected resources would also be authenticated in the same way. (Note that the client app would be able to pass in its c̲l̲i̲e̲n̲t̲ ̲i̲d̲ and c̲l̲i̲e̲n̲t̲ ̲s̲e̲c̲r̲e̲t̲ through the loginOptions parameter of AccountManager.getAuthToken(), which my custom authenticator would just pass to my resource provider, per the OAuth2 protocol).
Key Questions
Is it indeed possible for one app to obtain another app's authToken for an account by invoking AccountManager.getAuthToken() with the same authTokenType?
If this is possible, is this a valid/practical security concern within an OAuth2 context?
You could never rely on an auth token given to a user remaining secret from that user...so it's reasonable for Android to ignore this security by obscurity goal in its design --Michael
BUT - I'm not concerned about the user (the resource owner) getting the auth token without my consent; I'm concerned about unauthorized clients (apps). If the user wants to be an attacker of his own protected resources, then he can knock himself out. I'm saying it should not be possible that a user installs my client app and, unwittingly, an "imposter" client app that is able to gain access to my app's auth token simply because it passed-in the correct authTokenType and the user was too lazy/unaware/rushed to examine the access request screen. This analogy may be a bit oversimplified, but I don't consider it "security by obscurity" that my installed Facebook app cannot read emails cached by my Gmail app, which is different from me (the user) rooting my phone and examining the cache contents myself.
The user needed to accept an (Android system provided) access request for the app to use your token... Given that, the Android solution seems OK - apps can't silently use a user's authentication without asking --Michael
BUT - This is also a problem of authorization - the auth token issued for my "official" client is the key to a set of protected resources for which that client and only that client is authorized. I suppose one could argue that since the user is the owner of those protected resources, if he accepts the access request from a third party client (be it a "sactioned" partner app or some phisher), then he is effectively authorizing the third-party client that made the request to access those resources. But I have issues with this:
The average user is not security-conscious enough to be able to competently make this decision. I don't believe we should depend solely on the user's judgment to tap "Deny" on Android's access request screen to prevent even a crude phishing attempt. When the user is presented with the access request, my authenticator could be super-detailed and enumerate all the types of sensitive protected resources (that only my client should be able to access) for which the user will be granting should he accept the request, and in most cases, the user will still be too unaware and is going to accept. And in other, more sophisticated phishing attempts, the "imposter" app is just going to look too "official" for the user to even raise an eyebrow at the access request screen. Or, here's a more blunt example - on the access request screen, my authenticator could simply say, "Do not accept this request! If you are seeing this screen, a malicious app is trying to gain access to your account!" Hopefully, in such a case, most users would deny the request. But - why should it even get that far? If Android simply kept auth tokens isolated to the scope of each app/UID for which they were issued, then this would be a non-issue. Let's simplify - even in the case where I have just one "official" client app, and therefore my resource provider does not even worry about issuing tokens to other, third-party clients, as a developer I should have the option of saying to the AccountManager, "No! Lock-down this auth token so that only my app has access." I can do this if I go along the "custom tokens" route, but even in that case, I would not be able to prevent the user from first being presented with the access request screen. At the very least, it should be better-documented that the default implementation of AccountManager.getAuthToken() will return the same auth token for all requesting apps/UIDs.
Even the Android docs recognize OAuth2 as the "industry standard" for authentication (and presumably authorization). The OAuth2 spec clearly states that access tokens are not to be shared between clients or divulged in any way. Why, then, does the default AccountManager implemenation/configuration make it so easy for a client to obtain the same cached auth token that was originally obtained from the service by another client? A simple fix within the AccountManager would be to only re-use cached tokens for the same app/UID under which the they were originally obtained from the service. If there is no locally cached auth token available for a given UID, then it should be obtained from the service. Or at least make this a configurable option for the developer.
In the OAuth 3-legged flow (which involves the user granting access to the client), isn't it supposed to be the service/resource provider (and not, say, the OS) which gets to A) authenticate the client and B) if the client is valid, present the user with the grant access request? Seems like Android is (incorrectly) usurping this role in the flow.
But the user can explicitly allow apps to re-use a previous authentication to a service, which is convenient for the user.--Michael
BUT - I don't think the ROI in convenience warrants the security risk. In cases where the user's password is being stored in the user's account, then really, the only convenience that is being bought for the user is that instead of sending a web request to my service to get a new, distinct token that is actually authorized for the requesting client, a locally cached token that is not authorized for the client is returned. So the user gains the slight convenience of seeing a "Signing In..." progress dialog for a couple of seconds fewer, at the risk of the user being majorly inconvenienced by having his resources stolen/misused.
Keeping in mind that I am committed to A) using the OAuth2 protocol for securing my API requests, B) providing my own OAuth2 resource/authentication provider (as opposed to authenticating with say, Google or Facebook), and C) utilizing Android's AccountManager to manage my custom account type and its token(s), are any of my proposed solutions valid? Which makes the most sense? Am I overlooking any of the pros/cons? Are there worthwhile alternatives that I have not thought of?
[Use] Alternative clients Don't have a secret API that attempts to only be accessible to an official client; people will get around this. Ensure all your public facing APIs are secure no matter what (future) client the user is using --Michael
BUT - Doesn't this defeat one of the key purposes of using OAuth2 in the first place? What good is authorization if all potential authorizees would be authorized to the same scope of protected resources?
Has anyone else felt this was an issue, and how did your work around it? I've done some extensive Googling to try to find if others have felt this to be a security issue/concern, but it seems that most posts/questions involving Android's AccountManager and auth tokens are about how to authenticate with a Google account, and not with a custom account type and OAuth2 provider. Moreover, I could not find anyone that was concerend about the possibility of the same auth token being used by different apps, which makes me wonder whether this is indeed a possibility/worthy of concern in the first place (see my first 2 "Key Questions" listed above).
I appreciate your input/guidance!
In Response to...
Michael's Answer - I think the major difficulties I have with your answer are:
I am still inclined to think of apps as being separate, distinct clients of a service, as opposed to the user/phone/device itself being one "big" client, and therefore a token that has been authorized for one app should not, by default, be transferable to one that has not. It seems like you may be hinting that it is moot to consider each app as a distinct client because of the possibility that,
the user could be running a rooted phone, and read off the token, gaining access to your private API... [or] if the user's system was compromised (the attacker could read off the token in this case)
and that therefore, in the grand scheme of things, we should consider the device to be a client of the service since we cannot guarantee security between apps on the device itself. It's true if the system itself has been compromised, then there can be no guarantee of authenticating/authorizing requests being sent from that device to a service. But the same could be said, of say, TLS; transport security is irrelevant if the endpoints themselves cannot be secured. And for the vast majority of Android devices, which are not compromised, I believe it is more secure to consider each app client as a distinct endpoint, instead of lumping them all into one by sharing the same auth token.
When presented with the "access request" screen (akin to the software user license agreement that we always read thoroughly before consenting and installing), I don't trust the user's judgment to distinguish a malicious/unauthorized client app from one that is not.
Is this a valid/practical security concern?
For the official Client A, my OAuth2 provider may issue a "super" type/scope token which grants access to both public and private pieces of my API
In the general case, you could never rely on an auth token given to a user remaining secret from that user. For example - the user could be running a rooted phone, and read off the token, gaining access to your private API. Ditto if the user's system was compromised (the attacker could read off the token in this case).
Put another way, there's no such thing as a "private" API that is at the same time accessible to any authenticated user, so it's reasonable for Android to ignore this security by obscurity goal in its design.
a malicious app ... could obtain access to my app's stored OAuth2 token
For the malicious app case, it begins to sound more reasonable that a malicious app shouldn't be able to use the client's token, as we expect Android's permission system to provide isolation of malicious apps (provided the user read / cared about the permissions they accepted when they installed it). However, as you say the user needed to accept an (Android system provided) access request for the app to use your token.
Given that, the Android solution seems OK - apps can't silently use a user's authentication without asking, but the user can explicitly allow apps to re-use a previous authentication to a service, which is convenient for the user.
Possible Solutions Review
"Secret" authTokenType ... does not seem very secure
Agreed - it's just another layer of security through obscurity; it sounds like any app wishing to share your authentication would have had to look up what the authTokenType was anyway, so adopting this approach just makes it a bit more awkward for this hypothetical app developer.
Send client ID/secret w/ OAuth2 token ... [to] verify server-side that the app is the authorized client
This isn't possible in the general case (all the server gets is a series of messages in a protocol - the code that generated those messages can't be determined). In this specific instance, it might protect against the more limited threat of a (non-root) alternative client / malicious app - I'm not familiar enough with the AccountManager to comment (ditto for your custom auth tokens solutions).
Suggestion
You described two threats - malicious apps that a user doesn't want to have access to their account, and alternative clients that you (the developer) doesn't want using parts of the API.
Malicious apps: Consider how sensitive the service you are providing is, and if it's not more sensitive than e.g. Google / twitter accounts, just rely on Android's protections (permissions on install, Access Request screen). If it is more sensitive, consider whether your constraint of utilizing Android's AccountManager is appropriate. To strongly protect the user against malicious use of their account, try two factor authentication for dangerous actions (c.f. adding a new recipient's account details in online banking).
Alternative clients: don't have a secret API that attempts to only be accessible to an official client; people will get around this. Ensure all your public facing APIs are secure no matter what (future) client the user is using.
Your observation is correct. Authenticator will run with same UID as the installing app. When another app connects to Account manager and get token for this authenticator, it will bind to your provided authenticator service. It will run as your UID, so new accounts will be related to this Authenticator. When app calls for getAuthToken, binding will happen and Authenticator will still run in same UId. Default built in permissions check for account's UID, so that different Authenticator could not access another account from different Authenticator.
You can solve this issue with using "Calling UID" for addAccount and GetAuthToken since account manager service adds that to bundle. Your authenticator implementation can check that.
#Override
public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account,
String authTokenType, Bundle loginOptions) throws NetworkErrorException {
Log.v(
TAG,
"getAuthToken() for accountType:" + authTokenType + " package:"
+ mContext.getPackageName() + "running pid:" + Binder.getCallingPid()
+ " running uid:" + Binder.getCallingUid() + " caller uid:"
+ loginOptions.getInt(AccountManager.KEY_CALLER_UID));
...
}
I suggest to follow authorization flow instead of storing client secret in your native app, because other developers can extract that secret. Your app is not a web app and should not have secrets.
When you are adding an account, you can query the callingUId as well. You need to setUserData at your addAccount related activity which will be running as your app's UID, so it can call setUserData.
getUserData and setUserData uses built in sqllite database, so you don't need to build cache by yourself. You can only store string type, but you can parse json and store extra info per account.
When different third party app queries account and calls for getAuthtoken with your account, you can check UID in the account' userdata. If calling UID is not listed, you can do the prompt and/or other things to get permission. If it is permitted, you can add new UID to the account.
Sharing tokens between apps:
Each app is normally registered with different clientid and they should not share token. Token is for a client app.
Storage:
AccountManager is not encrypting your data. If you need more secure solution, you should encrypt the tokens and then store it.
I'm facing the same architectural problem for an app.
The solution that I got is to associate/hash the oauth token, with the app vendor token (ex. the token that facebook give to an app), and to device id (android_id). So only the app authorized, for the device is able to use the token from account manager.
Of course, it's just a new layer of security, but no bullet proof.
I reckon #Michael answered the question perfectly; however, to make the answer more sensible and short to those looking for a quick answer I am writing this.
Your concern about the security of android AccountManager is correct, but this is what OAuth is meant to be, upon which android AccountManager relies.
In other words, if you are looking for a very secure authentication mechanism this would not be a good option for you. You should not rely on any cached tokens for authentication, since they can be easily revealed to the intruder in case there is any security vulnerability on the user's device such as inadvertently granting access permission to the intruder, running a rooted device, etc.
The better alternative to OAuth in more secure authentication systems, e.g. online banking apps, is using asymmetric encryption using public and private keys, in which the user is required to enter their password every time for using the services. The password is then encrypted using the public key on the device and sent to the server. Here, even if the intruder gets known of the encrypted password, he cannot do anything with that because he cannot decrypt it with that public key and needs only the private key of the server.
Anyway, if one wants to make use of the AccountManager system of the android as well as maintain high level of security, it would be possible by not saving any tokens on the device. The getAuthToken method from AbstractAccountAuthenticator can then be overriden like this:
#Override
public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String
authTokenType, Bundle options) throws NetworkErrorException {
AuthenticatorManager authenticatorManager = AuthenticatorManager.authenticatorManager;
Bundle result;
AccountManager accountManager = AccountManager.get(context);
// case 1: access token is available
result = authenticatorManager.getAccessTokenFromCache(account, authTokenType,
accountManager);
if (result != null) {
return result;
}
final String refreshToken = accountManager.getPassword(account);
// case 2: access token is not available but refresh token is
if (refreshToken != null) {
result = authenticatorManager.makeResultBundle(account, refreshToken, null);
return result;
}
// case 3: neither tokens is available but the account exists
if (isAccountAvailable(account, accountManager)) {
result = authenticatorManager.makeResultBundle(account, null, null);
return result;
}
// case 4: account does not exist
return new Bundle();
}
In this method, neither case 1, case 2 nor case 4 holds true because there is no saved token, even though the account is there. Therefore, only case 3 will be returned which can then be set in the relevant callback to open an Activity in which the user enters username and password for authentication.
I am not sure of being on the right track in further describing this here, but my website posts on AccountManager may help just in case.

Options to securely authenticate mobile access using OAuth2

We're currently in the process of implementing OAuth2 to secure our new API and not sure how to securely provide required functionality. We need to allow the following from a mobile device:
Immediately after downloading the app the user is able to take a picture and submit it without having to first log in.
While we want to allow anonymous user access, where a user does not need to log in or register to use certain functionality, we do not want to allow unauthenticated access to the API. This would normally be accomplished using the client credentials authorization flow to obtain and app access token, however this requires knowing the client secret. From what I've read, a mobile device is not considered a trusted client and should not contain the client secret, and hence should not be able to generate an app access token on its own.
We've come up with a few options to accomplish this requirement, but would like some input on them:
Embed the client secret in the app. Doesn't seem ideal from a security standpoint, but maybe we're missing an obvious way to secure it? We're targeting at least iOS and Android.
Generate an app access token offline and embed that in the app. Still not very secure, but at least the secret isn't exposed.
Allow access to certain functionality using only the client ID instead of an access token. This may be the simplest, but it introduces an inconsistency and requires multiple ways of authenticating the client.
Build and use a companion web app to generate app access tokens for the mobile app. On the surface seems like a winner, but now you have to secure access to the companion app!
How would you securely authenticate access to an API using OAuth2 from a mobile device without requiring the user to first log in?
Agree with the comments on the Q. Either:
1.) Use Client Credentials grant type in OAuth 2 - with an embedded secret in your App. Understand that this isn't super secure and someone will reverse engineer it eventually. Ideally each client would get a unique secret - so you could revoke a client if they're abusing its use.
2.) Live with that API being open - thereby not requiring an OAuth 2 access token at all. Maybe that API would be known only to your app - but again, it would only be a matter of time before someone reverse engineers it.
My group is having a similar discussion. Users can get the app and browse a catalog without having to sign-in. The catalog and other data is accessed via an API and we would like to force users to have an access_token for all calls.
Our current thinking is to
Always force the App to exchange a common clientId/secret for an access_token. So the app would get an access_token even for anonymous users. This would be via the client_credentials oAuth flow.
If the user signs in, use the oAuth password flow. They would pass in clientId, secret, username, and password. We would additionally allow them to pass in their anonymous token so that we could transfer any history from their anonymous session.
So for example...
access_token = api.oAuth.client_credentials(clientId, secret)
catalog = api.getCatalog(access_token)
authenticated_access_token = api.oAuth.password(clientId, secret, username, password, access_token)

Categories

Resources