I am developing an Android app that integrates with users OneDrive for Personal account and obtains a Files.Read scope.
I have registered the app on Microsoft Application Registration Portal. Got a Client ID for authenticating my app with OneDrive and I am using Microsoft Graph APIs.
Now I have to include that Client ID in my app which would be distributed through Google Play.
How safe is that? If anyone can obtain that Client ID, is it possible for them to temper with the user's data by sending fake requests using that Client ID?
Please note that this concern is specifically for Client ID to authenticate requests to OneDrive.
Also, do these answers holds good here ?
Answer 1: https://stackoverflow.com/a/37945932/1363471
Just a remark: the client ID is not a secret by design, so actually
there is no need to protect it.
See section 2.2 in RFC 6749 ("The OAuth 2.0 Authorization Framework"):
The client identifier is not a secret; it is exposed to the resource
owner and MUST NOT be used alone for client authentication.
Answer 2: https://stackoverflow.com/a/14565249/1363471
I know this won't be a good StackOverflow answer, but I don't feel
able to explain it better than the Threat Model and Security
Considerations (RFC 6819). So here is the paragraph about obtaining a
Client Secret and its relative consequences.
Note that an Android app is a Public Client (a Native Application to
be more specific) so, as you say, unable to keep confidential its
credentials, but still able to protect Tokens and Authorization Code.
Answer #1 is correct, the Client ID is not a secret and you shouldn't be worried about packaging it inside your app. Its goal is to identify the client making the request, e.g. your app, not to authorize the call. The access token, which you get as the output of a successful OAuth flow and should be able to protect, is what's used to authorize the call.
Related
We are building a mobile application and its API server with architecture as in the picture below.
We have WSO2 as the API gateway in front of the Spring Boot API Server. We use WSO2 API Manager to restrict who can call the APIs. Only clients that have registered with our WSO2 and have the correct consumer key and secret can call an API through WSO2, by which the client first call to WSO2's token endpoint to exchange the consumer key and secret with an access token, then call the desired API with the access token in header Authorization: Bearer <access token>
We have a problem that we don't know how to keep the consumer secret since security audits prohibit us to store the secret in mobile app installer package.
There were some questions already asked such as
WSO2 API Manager - How does mobile app connect to API Manager?
WSO2 Api Manager OAuth2 DCR security in public native mobile app
But no answers correctly point to the problem. Most of them was mislead by the complexity of oauth2 flow.
To make the problem specific and clear, please assume that our mobile don't have users to login. The goal of this problem is to allow only trusted mobile application to call the API through WSO2.
Please help suggest if this is possible or not. Or we have no choice but to allow anyone to call the API. Or WSO2' consumer subscribtion feature is not designed to be used directly from mobile app at all?
After doing some research, I found 2 options people usually do.
Separate APIs into 2 groups. First group contains APIs that need to be used without user login, such as API to get initialization data or to get data for landing page of the app. Thease APIs are set as public, allow anyone to call without clientId and secret. The seconds group contains secured APIs that required the token. Mobile app can use Oauth2 PKCE flow to exchange the token with user identity proof.
Obfuscate clientId and secret and keep them in mobile app installer package. The APIs are still be separated into 2 groups as before. But the first group requires client-level token (oauth2 client credential type) and the second group requires user-level token (resource owner password or authorization code type)
I prefer option 2. In my opinion, I think the first option does not really make sense. People choosing this option, maybe, just do it to bypass the security audit check list, to not store the secret in public client, without really concern about security problem. It's like when you cannot trust your kids to keep a key to your house safely, so you decided to remove the lock from the door.
Having every APIs protected and keep the key in the client. Even though some hacker can manage to find the secret, he can only hack APIs of the first group and you can track the clientId he used. You know the expect behavior of the client so it is easy to setup an alarm that detect malicious activities from the client and revoke the token, reset the secret and rollout more complex obfuscation algorithm.
You may want to read OAuth 2.0 for Native Apps [RFC7636] spec. It states:
Public native app clients MUST implement the Proof Key for Code
Exchange (PKCE [RFC7636]) extension to OAuth, and authorization
servers MUST support PKCE for such clients, for the reasons detailed
in Section 8.1.
Check the below answer too.
How to implement Oauth2 without sending client_secret in WSO2 APIM
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).
I am developing a REST API secured via OAuth2 with Spring that will be used from an Android application (the client). In order to access any endpoint of my API, a OAuth2 access token is required and handed over to the endpoint via Authorization Header in a way similar to this:
"Authorization" - "Bearer accesstokenhere"
In order to acquire an access token, a username and password must be provided, as well as a client ID and client secret (they represent the Android app). The clientID and client secret are handed over to the token endpoint via Authorization Header in a way similar to this, which is specified by Spring:
"Authorization" - "Basic clientId:clientSecret"
If the client ID and client secret match a client defined on the server and if the user exists and the password is correct, access token and refresh token are returned.
Now my question is how I can securely store my clientId and client secret inside the Android application, making sure someone who reverse engineers my app does not get access to them?
Also, if I were to develop an iOS application (a second client), would it be wise to use a different clientID and client secret from a security POV?
You can't - even if there was a way, I could still just inspect the payload on the wire to determine the values. See section 8.5 of the OAuth 2.0 for Native Apps
Secrets that are statically included as part of an app distributed to multiple users should not be treated as confidential secrets, as one user may inspect their copy and learn the shared secret. For this reason, and those stated in Section 5.3.1 of [RFC6819], it is NOT RECOMMENDED for authorization servers to require client authentication of public native apps clients using a shared secret, as this serves little value beyond client identification which is
already provided by the "client_id" request parameter.
Your client id/secret parameters are just providing the identity of application making the request, as such it is recommended you'd want to create a different client for your iOS application, both from a security isolation point of view + for any analytics you want to gather about use of your application (e.g. 'how many sign in attempts are you retrieving by client id?' etc)
However, a threat actor could reverse engineer your settings, take your client id + secret and then start hitting your token endpoint with a username/password combo to attempt to brute force your application. If an endpoint accepts these values and returns a success/failure code, this is a useful attack vector for someone trying to compromise your system.
The current recommended approach is to use the 'Authorization code flow'
The best current practice for authorizing users in native apps is to
perform the OAuth authorization request in an external user-agent (typically the browser), rather than an embedded user-agent (such as one implemented with web-views).
Previously it was common for native apps to use embedded
user-agents (commonly implemented with web-views) for OAuth
authorization requests. That approach has many drawbacks,
including the host app being able to copy user credentials and
cookies, and the user needing to authenticate from scratch in each
app. See Section 8.12 for a deeper analysis of using embedded
user-agents for OAuth."
Have a look at AppAuth for Android for more information,
I have a simple Google App Engine backend (written in Python) for an Android client. All the backend is responsible for is accepting a key and returning a value; it is a classifier in general, implemented simply by looking up the key in a Cloud SQL table, though this specific behavior will change in the future.
The backend and client communicate via Google Cloud Endpoints. I want to restrict access to my backend's API to only accept requests incoming from my client, and am wondering if OAuth 2.0 is really the way to do this.
I don't need any contextual or extra information from the user, and as such, don't want to have user action to grant any type of authorization. All I need to do is be certain the request came from my app. I was considering simply generating a static key and hardcoding it in my client and backend, but I thought there must be a more elegant way to do this.
TL;DR: How can I restrict access to my backend only to my client/app without needing user context/input, by OAuth 2.0 or otherwise?
I don't know if the OP solved their problem but I am posting this here for others. I have wasted quite a few hours on this particular issue.
Steps :
1.Create an oAuth 2.0 client ID for your Android client.
2.Specify the Client IDs in the allowed_client_ids argument of the endpoints.api. In this case (Android), supply both its Android client ID and a web client ID in allowed_client_ids.
3.Supply the audiences argument as well in endpoints.api which is set to the web client ID.
4.Add a user check to the protected methods.
5.Redeploy the API backend.
6.Regenerate the client libraries.
New to OAuth2. I am writing an Android app that communicates with an App engine server application.
The app needs to authenticate itself with the server on behalf of the user, using Google account info of the user. The server needs to retrieve the user's basic info and create an account . That's the easy part and I know how to do this.
Furthermore, the Android app will also have the user authenticate himself/herself using Oauth2 and retrieve basic user info using Google account info of the user. I can do this as well.
This is where I need help Assuming the previous steps have been completed successfully, how can I use the Android app (where the user has logged in) to communicate with the server securely using the user's credentials.
Any ideas or am I missing something obvious?
The Android to App Engine OAuth2 communication is documented in this answer:
google app engine oauth2 provider
Using OAuth, 1.0 or 2.0, doesn’t matter in this, leads to the app obtaining an access token - then based on the API of your server, you pass this access token with requests instead of login and password. I guess the way to attach the access token string to URL requests may be slightly different between different APIs, see the documentation for yourself. Or if you are making the server app at the same time, then you need to figure out your way to do so (like sending a HTTP header Authorization: OAuth access_token=abcdefgh….