10
votes

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://tools.ietf.org/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?

3
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: stackoverflow.com/q/20558863/3040129 and stackoverflow.com/q/44312000/3040129illabout
@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

3 Answers

4
votes

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

1
votes

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??

0
votes

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.