5

I am trying to write a program that uses the Google Sheets API to read spreadsheets and operate on the data.

My program contains a credentials.json file which I obtained from the Java Quickstart page (also obtainable from the Google Developers Console). I cannot use the Sheets API without it.

I want to distribute my program to a few consumers. However, I am not sure what the risk is of distributing a program which contains this credentials.json file.

Anyone think he can enlighten me on the matter? Is there perhaps a safer alternative?

EDIT:

Looking the current answers, it seems that correct approach is OAuth 2.0. However, looking also at the Authorize Requests page and the Using OAuth 2.0 with the Google API Client Library for Java page, it seems that I still need to include some identification for my application before I can complete the authentication process. The only identification I know of is the API key and the client ID and client secret pair.

Just as a rule of thumb, I know I should not be distributing anything that has the word "secret" in it. That being said, I have seen other applications - such as Stackexchange - which you can authorize to access your account, and they are all able to identify themselves to Google Sign In. If these applications/sites can identify themselves to Google without presenting any security risks, then I am sure I can do the same.

Only one problem... How should I identify my application?

3 Answers3

3

I am a Google GDE Cloud Platform, security is my specialty.

The credentials.json file that you mention contains the Client ID and Client Secret. With this credential file, an attacker can create credentials for any Google Gmail/Gsuite/Identity email address. This will allow anyone with access to these secrets to create credentials with any "scope" they want and access/read/write/delete data in Sheets, Drive, etc. A hacker could host trojan software or distribute pornography from your account. Therefore distributing your application with this file is a very bad idea.

The correct approach is to implement OAuth 2.0 on your public web server, returning an Access Token to the user. The user then includes this Access Token in the HTTP Authorization header. Google Sheets verifies this token. This is not hard to do and there are many examples on the Internet. There are also free/almost free services such as Auth0 to do this for you.

[Update after question update]

There are two methods of doing things. The easy method and the secure method. I will discuss the secure method.

Do not provide private secrets of any form to the client. It is OK to provide the Client ID to the client as this is considered a public secret. The Client Secret must be protected.

The following is often called three-legged OAuth.

This means that OAuth is implemented at your web server (or a third party service). The client never sees the secrets. The client goes to a page on your website, your site redirects the user to Google, Google performs the authentication and calls back to a URL on your web server with the token information (Access Token, ID Token, Refresh Token).

Why do you want to implement OAuth this way? Google Sheets require the OAuth tokens have OAuth scopes and you do NOT want to permit a client program/browser to specify scopes. Scopes are permissions. You must control what permissions a client can have.

The opposite of three-legged OAuth is two-legged OAuth. This happens in the browser and is not secure for your requirements.

[Update on two-legged OAuth]

One item that was not specified in your question, is "whose" data is being accessed. If your app is accessing a user's private data, then the user is granting your app permission to access their data. If your app is accessing your private data, then you are granting the user permission to access your data.

If the use case is you are accessing the user's data, two-legged OAuth is OK (three-legged is the best method). This method can be completely implemented in the browser. However, for all OAuth methods, Google requires that you have a verified domain name and a website for customers to refer to. This once again makes three-legged OAuth the correct choice.

John Hanley
  • 320
  • 1
  • 6
  • Very interesting. However, this does not entirely resolve my dilemma. I updated the question. – Cardinal System Jun 20 '19 at 15:51
  • Yes, the application is going to be accessing the user's private data. I do not have a website/domain, so that is indeed a problem. Do I need a domain for two legged OAuth? – Cardinal System Jun 21 '19 at 16:30
  • Yes, you need a real domain with a website, privacy page, email address, etc. There are no exceptions to this. Technically, Google OAuth makes a callback to a URL with the tokens. This URL must be to a domain that you control - otherwise, where would they call back to?. Also, since your app is accessing a user's private data your application will have to be approved by Google. For some applications, not all, an audit by a Google approved third-party vendor might be required and this can cost in the range of $15K-$75K. – John Hanley Jun 21 '19 at 16:36
  • Well, I am not liking what I'm hearing. I might not be able to distribute my software. Thank you for your detailed answer! – Cardinal System Jun 21 '19 at 16:37
  • @CardinalSystem - There are lots of companies providing software that uses Google OAuth. Provided that you have a website, Google can background check your company, etc. I would not worry. Google's goal is to secure user's data and provided that you can show both the value in your product to users and security, everything should be OK. However, it is best to know the facts up front so that you can manage surprises later. – John Hanley Jun 21 '19 at 16:47
2

As other's have mentioned, the credentials.json file gives access to your account. It's not something you want to share with people. However there are two points worth clarifying:

Publishing it with your program is the same thing as sharing it

It's worth saying out loud that including it with your program is the same thing as sharing it. Granted, your average user isn't going to be able to pull it out of your app, but reverse engineering an app to grab credentials out of it is not just something that is quite possible, but it is something that absolutely happens. You should not put anything in your app that you don't want shared with the rest of the world. You don't want this shared with the rest of the world. Granted, it may be a long while before someone does reverse engineer your app and steal your credentials, it's not a risk worth taking. Especially because:

Including your credentials in your program won't work for your other users anyway

By including your credentials in the program, you are making a program that only works with your account. Obviously that's not what you're trying to do. The people you share your program with presumably want to use it to work with their data, not yours. So even ignoring the security issues involved with publishing your credentials with your program, you have a much more practical user-flow issue if you were to simply distribute your credentials with the program. In short, this is simply the wrong authentication method for a shared program anyway.

The solution

Fortunately the answer is easy: OAuth2, which Google supports (it's very common these days across just about every cloud service provider). The OAuth "protocol" was designed for this specific use case. It is intended to allow a Third Party App (which is what you built) to gain limited access to another user's account to perform actions on their behalf without having to actually ask the user for their credentials. A very stylized (and simplified) flow looks like this:

  1. The user opens your app and hits the "Login" button.
  2. Your app notifies Google that you would like to gain access to someone's account, and sends the user into the OAuth login flow which is hosted by Google
  3. The person signs in on Google's services with their google account
  4. Google then directs them back to your app along with a temporary access token which you can use on all API calls
  5. You also may have to refresh the access token depending on its maximum age and how long the user stays logged in.

The version of your program using OAuth and without your credentials file can then be safely shared with whomever you want. You would then login the same way as the rest of your users when you use the app yourself. Of course, you could also keep your original version of your app with your credentials built in if you wanted. That would allow you to use your program without having to login. If you do that though, just make sure you don't accidentally share it with everyone, since it contains your credentials.

Conor Mancone
  • 29,899
  • 13
  • 91
  • 96
  • I like what I'm seeing. I'll consider you for the bounty. However, I still require a little more info to solve my problem. The question has been updated. – Cardinal System Jun 20 '19 at 15:49
  • @CardinalSystem :) It's been a while since I've implemented an OAuth flow, and I've never done it with google, so I'll let John's answer stand. That would have been my suggestion anyway - have the app direct to a server you control to do the OAuth flow and return the final token back to the app. That way the process stays fully under your control the whole time. Of course, that does also require having some sort of webservice in place... – Conor Mancone Jun 20 '19 at 17:13
0

The credential json file is a full access token to a service account, this token can be used to access anything in your gcp account. Assuming you limit this user to the minimum needed to operate your account via google's iam you are safe. Furthermore I highly suggest putting this user outside every other Google project or permission group.

Jonathan Allon
  • 721
  • 3
  • 14