reactjsgoogle-mapssecuritygoogle-cloud-platformgoogle-cloud-functions

Hiding my API key from being accessed directly


My web app has a React frontend with a Node.js (Express) backend. My web app has a react-google-maps map. This map relies on an API key which I have created in my Google Cloud console. I created a backend function to fetch the API key needed. This part works as intended. The request works and the API key is inserted into the APIProvider and the map is displayed. It seems like the API key is not available in the web app which is great.

However, if I go Developer Tools > Network. I can find the backend request there and with it the link to the backend function: "https://examplesite/fetchApiKey". If I paste the URL into a web browser I am instantly presented with my API key in JSON format. How can I restrict access to this "website"/function?

A segment of my frontend code:

export function SokArrangement() {

  const [apiKey, setApiKey] = useState<string | null>(null);
  fetch('https://examplesite/fetchApiKey')
  .then(res => res.json())
  .then(data => {
    setApiKey(data.apiKey);
  });

... //other code

  return(
  ... //other code
  <APIProvider apiKey={apiKey} onLoad={() => console.log('Maps API has loaded.')}>
    <div style={{ height:"100vh", width:"100%" }}>
      <Map  defaultZoom={13}
        defaultCenter={ mapposition }
        mapId={"7ff7bc8394287bed"}>
        <ClusterMarkers addresses={addresses}/> //Generates various markers
      </Map>
    </div>
  </APIProvider>
  )
}

My backend code:

import { onRequest } from "firebase-functions/v2/https";
import express from 'express';
import cors from 'cors';

const app = express();
app.use(cors({
  origin: ['https://examplesite']
}));

app.get('/apiKey', (req, res) => {
  res.json({ apiKey: 'aPiKeYsTuFf123456789' });
});

export const getApiKey = onRequest(app);

In GCP under APIs and Services > Credentials, I have applied application restrictions so the key should only be able to be used by my frontend website. I think this should prevent abuse to an extent, though it would be nice if the key was entirely hidden.

I think I have to do something under Cloud Run Functions > Permissions, but I don't know what since I can only change permissions to certain Google accounts. Under Cloud Run I can restrict "Ingress" and "Authentication" which successfully restricts access, but then I don't know how to permit my site to make calls to the function.


Solution

  • Google cloud API keys must be in your front-end code, even the Google Maps sample code has an unprotected api key, and it is safe to include as long as it is properly restricted.

    Sample code: https://github.com/googlemaps-samples/codelab-maps-platform-101-react-js/blob/main/solution/src/app.tsx

    You can see more ways to restrict your api key access here: https://developers.google.com/maps/documentation/javascript/get-api-key#restrict_key Make sure to restrict your api key to the specific referrer URLs

    You can also implement rate limiting: https://developers.google.com/maps/documentation/javascript/usage-and-billing#set-caps