6

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?

Greg Moens
  • 1,705
  • 8
  • 15

3 Answers3

2

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.

John Hanley
  • 74,467
  • 6
  • 95
  • 159
  • 2
    In my particular case, I don't have a web server. The mobile app authenticates and then hits Google APIs directly and displays data right in the app. If another app used my client ID, it would link that API activity back to my Google Cloud project, meaning there would be billing implications against me. That's what I'm mostly worried about. Does that change things? – Greg Moens Dec 05 '18 at 01:32
  • Your app allows anyone with a Google Account to access your services on Google? I would rethink that design immediately. In this case you have no security or accountability. Anyone can create a Google Account which means anyone can access your project. What is the point of using OAuth then? The final goal of implementing OAuth is `authentication` and `authorization` and `accounting` (AAA). If you are allowing anyone access to anything, what are you accomplishing other than testing a client's intent by making then login. – John Hanley Dec 05 '18 at 01:39
  • To add some humor to this. You are installing a lock on your front door and then putting the key in the lock. – John Hanley Dec 05 '18 at 01:46
  • No, the user is accessing their own data. But I was under the impression that those API calls that I make on Google's servers on the users behalf would count against my developer account's quota. I could be way off on that and maybe that's why I'm confused. – Greg Moens Dec 05 '18 at 01:47
  • 1
    On the point of billing, I don't know and I should. However, if they are accessing their own data and you are using their token (which they authorized) you should be OK. The authentication screen displays what `scopes` your application is requesting to the client. `Maybe one of the Google Support team members will comment on this thread`. – John Hanley Dec 05 '18 at 01:56
  • There's also a public perception consideration. In my Google developer project I need to specify my app name and logo. That info is displayed during the authentication flow. It also displays when a user is reviewing which apps they've given access to their Google account. If a malicious app used my client ID, it's my app name and logo that account access would be tied back to. Now maybe that's not my concern either, as you said in your answer, "the client should use good judgement". – Greg Moens Dec 05 '18 at 02:13
  • 1
    Unfortunately I am not an Android (or IOS) developer. In my world (web / desktop / server) we use digitial signatures to sign our products or SSL Certificates to prevent forgery. Items like your App Name, Logo, etc. are very easy to acquire. The problem that I see for you is that you do not control any part of the process. This is why I strongly recommend at least a server that manages authorization and accounting for your authenticated clients. – John Hanley Dec 05 '18 at 02:28
  • Thanks for the discussion. I guess I was over complicating things. The user is authorizing access to their own data and it's about trust in my app, not my client ID. – Greg Moens Dec 05 '18 at 14:44
  • 7
    The initial question is a valid one, and this answer does not answer it so I downvoted it. As @GregMoens says, I can steal his client ID and use it in my own OAuth app, pretending to be his app. The user will then trust *me*, when in fact I am not an app approved by Google. Traditionally `client_secret` is supposed to guarantee that I am the owner of the client app, but as the original question states, PKCE doesn't use the `client_secret`. Answering the question by "use server authorization instead of PKCE" is not a valid answer and is ignoring why PKCE was born in the first placed. – ashiina Feb 19 '20 at 10:13
  • 3
    I agree with @ashiina. I'm implementing my own OAuth2 server, and the client secret is typically the main bulwark against attackers. On mobile, there is no client secret and deep-linked redirect URIs can't be securely validated. PKCE is not the answer either, as it doesn't stop an attacker with another developer's client ID from gaining access to, and even control over, users' private information once they log in. Yes, users need to be more security conscious, but that isn't really an excuse to dismiss a clear loophole in the OAuth2 process which is designed to keep users' information secure. – brandav Apr 04 '20 at 03:01
  • @JohnHanley So any email client that wants to be able to access Gmail needs a backend server? – Melab Jul 06 '22 at 17:22
  • @Melab - Your comment is missing context. If the secrets are the clients, no problem. Create a new question with details. – John Hanley Jul 06 '22 at 23:34
1

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:

Gary Archer
  • 22,534
  • 2
  • 12
  • 24
  • I think it makes sense to add link to [your other answer here](https://stackoverflow.com/a/66179095/12092416). Thank you! – Sergei Jan 10 '22 at 09:35
1

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).