DEV Community

loading...

Is it safe to use Google APIs from Client-Side Javascript πŸ€” ❓

bauripalash profile image Palash Bauri πŸ‘» ・1 min read

Today I was experimenting with APIs , and landed on https://developers.google.com/drive/api/v3/quickstart/js while learning about Google Drive API. After reading the code example on that page , I was concerned about exposing my API Key and Client ID to public.

<!DOCTYPE html>
<html>
  <head>
    <title>Drive API Quickstart</title>
    <meta charset="utf-8" />
  </head>
  <body>
    <p>Drive API Quickstart</p>

    <!--Add buttons to initiate auth sequence and sign out-->
    <button id="authorize_button" style="display: none;">Authorize</button>
    <button id="signout_button" style="display: none;">Sign Out</button>

    <pre id="content" style="white-space: pre-wrap;"></pre>

    <script type="text/javascript">
      // Client ID and API key from the Developer Console
      var CLIENT_ID = '<YOUR_CLIENT_ID>';
      var API_KEY = '<YOUR_API_KEY>';

      // Array of API discovery doc URLs for APIs used by the quickstart
      var DISCOVERY_DOCS = ["https://www.googleapis.com/discovery/v1/apis/drive/v3/rest"];

      // Authorization scopes required by the API; multiple scopes can be
      // included, separated by spaces.
      var SCOPES = 'https://www.googleapis.com/auth/drive.metadata.readonly';

      var authorizeButton = document.getElementById('authorize_button');
      var signoutButton = document.getElementById('signout_button');

      /**
       *  On load, called to load the auth2 library and API client library.
       */
      function handleClientLoad() {
        gapi.load('client:auth2', initClient);
      }

      /**
       *  Initializes the API client library and sets up sign-in state
       *  listeners.
       */
      function initClient() {
        gapi.client.init({
          apiKey: API_KEY,
          clientId: CLIENT_ID,
          discoveryDocs: DISCOVERY_DOCS,
          scope: SCOPES
        }).then(function () {
          // Listen for sign-in state changes.
............. βœ‚οΈ ...........
Enter fullscreen mode Exit fullscreen mode

So, Is it really safe to use code like this in public facing production webapps? πŸ€”πŸ€”

Discussion (6)

pic
Editor guide
Collapse
tiguchi profile image
Thomas Iguchi • Edited

This is a common problem with client applications. The same problem also affects mobile apps. Consider API keys and other secrets not to be secret anymore when you decide to bundle them with your client apps. See also: developer.okta.com/blog/2019/01/22...

However, when you set up Google Drive API credentials for the first time Google guides you through a small questionnaire and also asks you how and from where you want to access their APIs:

Screenshot of Google API credentials setup wizard

One of those options is "Web browser (JavaScript)". When you select that option the only credential you are offered is the client ID, which is not a secret. It's basically just a unique identifier for your application. You can safely embed that in your JS code. Nothing to worry about.

Have you tried that instead? Does it work in your case?

Other than that, just in principle when you're dealing with 3rd party API keys and secrets, your best bet is to run your own web server and web API, and let that talk to 3rd party APIs on behalf of your client app.

That way you don't expose your secrets. However, it's up to you to implement your own auth schemes in order to limit and guard access to your own web API.

In case of Google Drive access, you're basically asking your end users to trust your app with their confidential documents. Here it's a bit more reassuring to let your client app do the talking directly with Google's API, and not through your service as a man in the middle.

Collapse
vamsikrish profile image
Vamsi Krishna

I wouldn't use SECRETS on the Client-Side since they risk exposing for the end-users. You can write a wrapper in Back-End stack like nodejs, c# etc and call those from your front-end and allow only your particular origin to that wrapper api and makesure your wrapper api has authentication so people cant bypass CORS from postman and such things.

Collapse
exadra37 profile image
Paulo Renato • Edited

so people cant bypass CORS from postman and such things.

Unfortunately they can be bypassed:

medium.com/netscape/hacking-it-out...

In my case, I forked the repo and added a configuration option that allows you to spoof the Origin header, which defaults to true. You can check it out here. I also hosted this on Heroku as cors-escape.herokuapp.com (nothing to see there πŸ˜€).

So basically you cannot spoof it directly with JavaScript in the browser, but you can do it in a programmatically way.

Regarding Postman I am not aware if it allows or not to fake the origin header.

The lesson to take from here is that the CORS is a good protection on the browser side but not that hard to bypass.

The WHO vs WHAT Is Accessing the API Server

A usual misconception among developers it's WHO vs WHAT is accessing the API server.

For a better understanding off the difference between WHO vs WHAT is accessing your API server, I recommend you to read this section of my article, but I will extract here some lines of it:

The who is the user of the mobile app that we can authenticate, authorize and identify in several ways, like using OpenID Connect or OAUTH2 flows.

The what is the thing making the request to the API server. Is it really a genuine instance of your mobile app, or is a bot, an automated script or an attacker manually poking around your API server with a tool like Postman?

Without going into more detail, I want to say that any API server will have a hard time to figure out the WHAT bit, that will misuse and abuse of WHO the API server thinks is talking with.

Collapse
vamsikrish profile image
Vamsi Krishna • Edited

I know we can bypass CORS from tools like postman since it is browser based protection only so I wanted to say to add authentication since cors will be bypassed from other means of making calls. Maybe my framing of sentence made you think I was saying cors can’t be bypassed

Thread Thread
exadra37 profile image
Paulo Renato

Maybe my framing of sentence made you think I was saying cors can’t be bypassed

Yes, it made me thought that you believed that CORS was enough to protect the API.

Collapse
sneezeaway profile image
Garyyyyyyy

I think it’s always good to put your API keys in .env file or other places. Safety concerns if you put it in the client side.