20

I was looking for some best practices sample code about how to design and create my own desktop app (or installed app) in Python requiring OAuth 2.0 Authorization flow to Google, and found this repository provided by Google : https://github.com/googlesamples/oauth-apps-for-windows (coded in C#, but anyway the design should be the same).

When diving into the code, I was surprised to see that the client_secret was directly embedded, in clear, into the source code (take a look here : https://github.com/googlesamples/oauth-apps-for-windows/blob/e79f1575b5858c5f617d29f2435a93996e4248c5/OAuthConsoleApp/OAuthConsoleApp/Program.cs#L47).

I have found this on Google Developers documentation about "Installed applications" :

When you create a client ID through the Google API Console, specify that this is an Installed application, then select Android, Chrome, iOS, or "Other" as the application type. The process results in a client ID and, in some cases, a client secret, which you embed in the source code of your application. (In this context, the client secret is obviously not treated as a secret.)

Also, I don't know why Android or iOS applications does not include this client_secret in the OAuth Client ID generated from the console, and other native applications (desktop) should.

And I have also found in many websites that the client secret should be kept ... secret, as its name implies.

I have read the different RFCs for native apps (most reliable source I believe) and found this useful :

https://datatracker.ietf.org/doc/html/draft-ietf-oauth-native-apps-12#appendix-A :

  1. Not assume native app clients can keep a secret. If secrets are distributed to multiple installs of the same native app, they should not be treated as confidential. See Section 8.5.

But I'd like to be sure I understand correctly.

So, after generating the OAuth Client Id for "other" application type from the Google API Console, is it ok to embed the client secret directly in my app? Is there really no security issues by doing this? This SO post : What the attacker could do if he obtains application's client_secret? talks about security issues, so I'm a little bit lost.

Using google-auth-oauthlib to avoid implementing OAuth protocol from scratch, can I distribute safely the following code (**** values will not be obfuscated obviously) :

from google_auth_oauthlib import flow

# generated from Google API Console ("other" application)
client_config = {
  "installed": {
    "client_id": "****.apps.googleusercontent.com",
    "client_secret": "****", # is it safe?
    "project_id": "****",
    "auth_uri": "https://accounts.google.com/o/oauth2/auth",
    "token_uri": "https://oauth2.googleapis.com/token",
    "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
    "redirect_uris": [
      "urn:ietf:wg:oauth:2.0:oob"
    ]
  }
}

scopes = ['https://www.googleapis.com/auth/books'] # example
appflow = flow.InstalledAppFlow.from_client_config(client_config, scopes=scopes)
appflow.run_console()
credentials = appflow.credentials

# some code requesting Google APIs for the required scopes

If a malicious user found the client_secret, what can he do with this?

Community
  • 1
  • 1
norbjd
  • 10,166
  • 4
  • 45
  • 80
  • 1
    I had this exact same question. The following two answers seem to suggest that the `client_secret` doesn't need to be kept secret for native applications: https://stackoverflow.com/q/20558863/3040129 and https://stackoverflow.com/q/44312000/3040129 – illabout Mar 07 '20 at 14:43
  • 1
    @illabout thanks for the useful links. I still do not understand the difference between Android/iOS (that does not include the `client_secret`) and desktop apps (requiring to embed `client_secret`). Like said in one of the posts you provided, it looks like it's an "oddity". Also, my main concern is about security, I don't know what a malicious user can do with that `client_secret`, even if this case it is not considered as a real "secret". I can't find any reliable source (expected the RFC) talking about this. – norbjd Mar 08 '20 at 09:56
  • 1
    @norbjd What solution did you eventually land on for this? I've been running in circles trying to answer this question and I just don't feel like I can ever learn enough to sort it out. – Aaron Ciuffo Dec 08 '21 at 09:53
  • 2
    @AaronCiuffo In our case, we decided to add the client_secret inside the source code like in the Google sample. But users of this application were users from our company, so the risk of doing something bad with the client_secret is mitigated because only few known users used our app. – norbjd Dec 08 '21 at 11:53
  • 1
    @norbjd I guess there's just not enough demand for user-land google apps for there to be a better solution for this. That's a little frustrating, but I'll have to live with it unless I want to make my app web-based. – Aaron Ciuffo Dec 08 '21 at 12:47

3 Answers3

8

When public clients (e.g., native and single-page applications) request Access Tokens, some additional security concerns are posed that are not mitigated by the Authorization Code Flow alone. This is because:

Native apps
Cannot securely store a Client Secret. Decompiling the app will reveal the Client Secret, which is bound to the app and is the same for all users and devices. May make use of a custom URL scheme to capture redirects (e.g., MyApp://) potentially allowing malicious applications to receive an Authorization Code from your Authorization Server.

Single-page apps
Cannot securely store a Client Secret because their entire source is available to the browser.

To mitigate this, OAuth 2.0 provides a version of the Authorization Code Flow which makes use of a Proof Key for Code Exchange (PKCE) (defined in OAuth 2.0 RFC 7636).

The PKCE-enhanced Authorization Code Flow introduces a secret created by the calling application that can be verified by the authorization server; this secret is called the Code Verifier. Additionally, the calling app creates a transform value of the Code Verifier called the Code Challenge and sends this value over HTTPS to retrieve an Authorization Code. This way, a malicious attacker can only intercept the Authorization Code, and they cannot exchange it for a token without the Code Verifier.

Further reading : https://auth0.com/docs/flows/concepts/auth-code-pkce

Akashdeep S
  • 81
  • 1
  • 3
  • 3
    Your explanations are perfectly clear but Google's implemetation, contrary to others (e.g. Dropbox) is such that once the Authorization Code is received, exchanging it for a token requires that the client sends its private key. Consequently, that key must be embedded in the distributed app (and obfuscating it is a waste of time because it can be reverse engineered). I find Google's sentence "In this context, the client secret is obviously not treated as a secret." laughable coming from a company that claims to teach security - https://developers.google.com/identity/protocols/oauth2 – Vicne Jun 20 '20 at 16:15
  • 2
    I don't understand that part either. When you embed both a client ID and client secret in the source code, what stops bad actors from copying these credentials into their own apps and let their users make as much API calls as possible until it reach the limit? – bytrangle Jul 10 '21 at 04:25
  • @Akashdeep S can you elaborate a bit more? I'm writing an open source python project. I'm still a little hazy this. Is the client_secret is actually a secret, and can be abused if it's out in the wild. What's to stop someone from using my publicly available client_secret in their own project? – Aaron Ciuffo Dec 05 '21 at 11:39
  • PKCE only prevents interception of an authorization token from another party that might be embedded on the same device, which is useful, but does not answer the original question. As far as I can tell, this question has no answer yet. The responsibility would largely fall on the resource owner to not install malicious software impersonating your app. – myoungberg Sep 16 '22 at 20:11
1

I have the same issue with Google requiring client_secret for desktop apps. While an attacker obviously cannot get confidential information with a client_secret, could he not launch a denial-of-service attack by generating a large number of spurious requests with that client_secret and causing Google to block it? That would require the developer to create a new client secret and redistribute to all users??

yegodz
  • 5,031
  • 2
  • 17
  • 18
  • have you found a solution or best practice for this? I'm trying to create an open source application that I can distribute, but it's pretty useless if end users have to sort out how to create their own key and then build the app themselves. – Aaron Ciuffo Dec 08 '21 at 09:51
  • This does not answer the question. – Robin Zimmerman Jan 15 '23 at 22:11
0

There isn't any particular user data attached to the client secret as anyone using the client_id and client_secret will need to authenticate with their Google account via OAuth screen.

But the actual issue seems to be that you are accessing Google APIs with the generated credentials and those API calls are not for free. At the end your application is billed for the API calls made by the users authenticated via your application.

  • 1
    Thanks for your answer. Are you sure about the billing part ? Do you have any reliable source for the first and second part of your answer ? Thank you very much. – norbjd May 13 '20 at 07:46
  • It's not written in their docs, but some APIs like Google Maps requires setting up a billing. You can't make any API request to Google Maps if you don't have it, even when your users are authenticated. You receive $X credit to get started, so obviously those API calls are not for free. – bytrangle Jul 10 '21 at 04:31