API Key Hiding

Introduction

One of the most common usages of the what3words API is within browser based applications. For example, you might be using the what3words autosuggest jQuery plugin to allow easy capture of 3 word addresses on your website. In cases such as these, where a client side JavaScript application is making calls to the public what3words API, there is a danger that you're API key will be both visible inside your JavaScript application, and over the network.

To mitigate against this it is possible to hide your API key by proxying API calls through a proxy application running on your server.

Sample code

					
<?php 
	// Extract the what3words API method - forward, reverse, etc
	$method = explode('/', trim($_SERVER['PATH_INFO'],'/'))[0];

	// The what3words API URL
	$base_url = 'https://api.what3words.com/v2/';

	// Exract URL parameters to be passed onto the request
	$params = "";
	foreach ($_GET as $key=>$value) {
		$params = $params . $key . '=' . urlencode($value) . '&';
	}

	// The what3words API key to use
	$key = 'MY-API-KEY';

	// Build up the URL to proxy
	$url = $base_url . $method . '?' . $params . 'key=' . $key;

	$curl = curl_init();
	$headers = [];

	curl_setopt_array($curl, array(
		CURLOPT_URL => $url,
		CURLOPT_RETURNTRANSFER => true,
		CURLOPT_ENCODING => 'UTF-8',
		CURLOPT_MAXREDIRS => 10,
		CURLOPT_TIMEOUT => 30,
		CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
		CURLOPT_CUSTOMREQUEST => 'GET',
	));

	// Read the headers back from the response
	curl_setopt($curl, CURLOPT_HEADERFUNCTION,
		function($curl, $header) use (&$headers)
		{
			$len = strlen($header);
			$header = explode(':', $header, 2);
			if (count($header) < 2) // ignore invalid headers
				return $len;

			$name = strtolower(trim($header[0]));
			if (!array_key_exists($name, $headers))
				$headers[$name] = [trim($header[1])];
			else
				$headers[$name][] = trim($header[1]);

			return $len;
		}
	);

	// Call the what3words API with the proxied request
	$response = curl_exec($curl);

	// Mimic the content type header from the actual API response
	$content_type = $headers['content-type'][0];
	header('Content-Type:' . $content_type);

	/** 
	* Return appropriate CORS headers if the proxy is hosted on a different 
	* domain to the website initiating the AJAX request
	*/
	$allowed_origin = 'example.com';
	header('Access-Control-Allow-Origin:' . $allowed_origin);

	echo $response; 	
?>					
				

Setup

The example provided here is written in PHP. Whilst no PHP dependencies are required, it is assumed that you have a working environment to host PHP from.

You will need a what3words API key, which should be assigned to the $base_url variable. If you don't already have an API key, you can obtain one by registering for an account.

Usage

Assuming you have the above PHP script running on your webserver, in a file called w3w_proxy.php, you should be able to call it with any valid what3words API HTTP GET request. For example, to make a forward geocode, you could make the following HTTP request: -

https://<domain>/w3w_proxy.php/forward?addr=index.home.raft

CORS

It is important efforts are taken to make sure other websites are not able to make use of your proxy.

By default, web browsers permit scripts contained in a first web page to access data from a second source, but only if both sources have the same origin. Therefore, by default, only web pages served from the same domain as your proxy will be able make successful AJAX through the proxy.

If however, you are hosting your proxy on a different domain to your website, you will need to add the Access-Control-Allow-Origin header (with the value of your websites domain) to your proxies response headers. This is allows the browser to access your resource (the proxy), even though the request is coming from a different domain. The following code snipit demonstrates how this can be achieved.

$allowed_origin = 'example.com';
header('Access-Control-Allow-Origin:' . $allowed_origin);