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).
Related
TL;DR - How can I refresh tokens backend-side if the oauth2 authorization happens in native android/ios app?
I am working on oauth2 integration with google calendar. My stack is react SPA app as web client and we have a backend API (in elixir). We are also using hybrid native apps, so our JS code is transformed into corresponding iOS/Android apps (using capacitor).
The flow is as follows:
user authorizes us to modify their calendars using oauth2, we ask for offline access
we acquire client-side authorization code from google
we send it to our backend and it uses the auth code to acquire access token and refresh token, the tokens are then persisted in our DB
we use the access token to perform updates to google calendar. When token expires we refresh it backend-side
This is the flow that is working on the web client, but with native apps (android/ios) I am stuck. When I use corresponding to ios/android apps clientIds from google console project credentials, my backend cannot successfully use it to acquire refresh and access tokens, I get the following response from https://oauth2.googleapis.com/token:
%{"error" => "invalid_client", "error_description" => "Unauthorized"}
I am considering moving the process of exchanging authorization code to refresh token and access token to the native apps, but how can the backend then have access to new access tokens? I can't refresh the tokens backend side if they were generated in the native app, I will again have clientId mismatch (also backend uses clientSecret, while native apps are exempt from using clientSecret).
You cant. The refresh token is client id based. You need the client id and client secret that were used to create it in order to refresh it.
The client used for Ios and android apps doesn't have a client id and secret that you could use backend.
You can do it the other way around though. If you created the refresh token in your backend app. The ios and android apps could refresh it as long as the client id is part of the same project.
I suspect there is something internal in the android and ios sdk's that allow for this. It just doesn't work with any other type of client due to the lack of client secret.
take a look at this documentation, it works form me in the same problem.
https://developers.google.com/identity/sign-in/ios/offline-access
"On your app's backend server, exchange the auth code for access and refresh tokens. Use the access token to call Google APIs on behalf of the user and, optionally, store the refresh token to acquire a new access token when the access token expires."
serverAuthCode is used on this api https://developers.google.com/identity/protocols/oauth2/native-app#exchange-authorization-code to generate a new refresh_token
I had the same issue and finally ended up.
In order to design user authentication from the mobile/front-end side and send the authorization code to the server-side to exchange it for access_token and referesh_token you have not to follow the Mobile or Installed App flow:
In this way, you've created Android app OAuth2 credentials in the google developer console and used its client_id for google oauth2 page preparation so at the end you will have access_token which works only on the mobile side and does not work on the backend as it doesn't have client_secret.
Therefore, if you want to have access to the google APIs on your server-side and just perform the google authentication on the mobile side you can choose one of the following flows:
As you can see from the above flows, there are three parts namely client-side (mobile), google, and server-side (backend) rather than communication just between mobile and google which is useful for installed applications, not web applications. To me, between these two flows, I prefer the last one as it has fewer requests to create access_token and refresh_token on the server-side.
Here's the whole procedure:
create a web application oauth2 credentials on the google developer console and use all sections in the backend and the client_id on the mobile side as well. Don't forget to enable the API you want to use.
create a /callback endpoint in the backend which is the same as redirect_uri that you will need on the mobile side. In this endpoint, you will get the authorization code from the google request and then exchange it to the access_token and referesh_token and persist that on the DB.
create an endpoint in order to call google API such as google calendar.
Bring up the google authorization page on the mobile using SDKs, web view, or browser with the following content: existing client_it (which is the same with server-side), redirect_uri (callback), response_type="code", scope="https://www.googleapis.com/auth/calendar", access_type="offline", include_granted_scopes=true, and state to put some string if you want, for example I sent user's uuid.
You can obtain access_token using refresh token by sending
POST https://oauth2.googleapis.com/token
x-www-form-urlencoded
client_id:CLIENTID
refresh_token:REFRESHTOKEN
grant_type:refresh_token
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 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 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.
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.