user93453
user93453

Reputation: 46

GCP api key restrictions

In my GCP project, I created a new api key. I restricted the key to IOS apps, and properly set my IOS application bundle id.

The api key is being used in an Ionic 5 app, which has been built in Xcode and is running on an IOS device.

The api key is being passed on a Google Maps static API request.

To test the api key restriction I crafted a url that looks like this:

https://maps.googleapis.com/maps/api/staticmap?center=290%20Bremner%20Blvd%2C%20Toronto%2C%20ON%20M5V%203L9&key=[restricted key here]&zoom=12&size=400x400

When I load this url from my laptop web browser a map is returned, but I expected this not to work, and instead that I would receive an http 403 error.

Any insight into what I'm missing here appreciated; how do I properly restrict my maps api key when using it in an Ionic 5 app?

Upvotes: 0

Views: 732

Answers (1)

user93453
user93453

Reputation: 46

I found the answer to my question: in addition to using a restricted API key, each Maps Static API request must be digitally signed when making the request.

Here's sample Node js code from Google on how to do this:

'use strict'

const crypto = require('crypto');
const url = require('url');

/**
 * Convert from 'web safe' base64 to true base64.
 *
 * @param  {string} safeEncodedString The code you want to translate
 *                                    from a web safe form.
 * @return {string}
 */
function removeWebSafe(safeEncodedString) {
  return safeEncodedString.replace(/-/g, '+').replace(/_/g, '/');
}

/**
 * Convert from true base64 to 'web safe' base64
 *
 * @param  {string} encodedString The code you want to translate to a
 *                                web safe form.
 * @return {string}
 */
function makeWebSafe(encodedString) {
  return encodedString.replace(/\+/g, '-').replace(/\//g, '_');
}

/**
 * Takes a base64 code and decodes it.
 *
 * @param  {string} code The encoded data.
 * @return {string}
 */
function decodeBase64Hash(code) {
  // "new Buffer(...)" is deprecated. Use Buffer.from if it exists.
  return Buffer.from ? Buffer.from(code, 'base64') : new Buffer(code, 'base64');
}

/**
 * Takes a key and signs the data with it.
 *
 * @param  {string} key  Your unique secret key.
 * @param  {string} data The url to sign.
 * @return {string}
 */
function encodeBase64Hash(key, data) {
  return crypto.createHmac('sha1', key).update(data).digest('base64');
}

/**
 * Sign a URL using a secret key.
 *
 * @param  {string} path   The url you want to sign.
 * @param  {string} secret Your unique secret key.
 * @return {string}
 */
function sign(path, secret) {
  const uri = url.parse(path);
  const safeSecret = decodeBase64Hash(removeWebSafe(secret));
  const hashedSignature = makeWebSafe(encodeBase64Hash(safeSecret, uri.path));
  return url.format(uri) + '&signature=' + hashedSignature;
}

More information / documentation here:

https://developers.google.com/maps/documentation/maps-static/get-api-key#gen-sig

Upvotes: 0

Related Questions