I want to make GET, POST & PUT calls to a 3rd party API and display the response on the client side via AJAX. The API calls require a token, but I need to keep that toke
From your requirements it looks like "server-side code in the middle" relay(proxy) script is the best option.
PHP example here. N.B. to handle CURL errors it returns a new "object" comprising ['status'] ('OK' or info on CURL failure) and ['msg'] containing the actual response from the API provider. In your JS the original API "object" would now require extracting one level down under 'msg'.
Basic Relays/Proxies can be circumvented
If you use a relay script then someone looking for an API key will probably try elsewhere. However; the pirate could simply replace his call to the API provider using your API key, with a call to your script (and your API key will still be used).
Running of your AJAX/relay script by search engine bots
Google bots (others?) execute AJAX. I assume (relay or not) if your AJAX does not need user input then bot visits will result in API key usage. Bots are "improving". In future (now?) they might emulate user input e.g. if selecting a city from a dropdown results in API request then Google might cycle thro dropdown options.
If of concern you could include a check in your relay script e.g.
$bots = array('bot','slurp','crawl','spider','curl','facebook','fetch','mediapartners','scan','google'); // add your own
foreach ($bots as $bot) :
if (strpos( strtolower($_SERVER['HTTP_USER_AGENT']), $bot) !== FALSE): // its a BOT
// exit error msg or default content for search indexing (in a format expected by your JS)
exit (json_encode(array('status'=>"bot")));
endif;
endforeach;
Relay script and additional code to cater for above issues
Do not overdo pirate protection; relays should be fast and delay unnoticeable by visitors. Possible solutions (no expert and rusty with sessions):
1: PHP sessions solution
Checks whether relay is called by someone who visited your AJAX page in last 15 mins, has provided a valid token, and has the same User Agent and IP Address.
Your Ajax Pages add the following snippets to your PHP & JS:
ini_set('session.cookie_httponly', 1 );
session_start();
// if expired or a "new" visitor
if (empty($_SESSION['expire']) || $_SESSION['expire'] < time()) $_SESSION['token'] = md5('xyz' . uniqid(microtime())); // create token (fast/sufficient)
$_SESSION['expire'] = time() + 900; // make session valid for next 15 mins
$_SESSION['visitid'] = $_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT'];
...
// remove API key from your AJAX and add token value to JS e.g.
$.ajax({type:"POST", url:"/path/relay.php",data: yourQueryParams + "&token=", success: function(data){doResult(data);} });
The relay/proxy Script (session version):
Use an existing example relay script and before the CURL block add:
session_start(); // CHECK REQUEST IS FROM YOU AJAX PAGE
if (empty($_SESSION['token']) || $_SESSION['token'] != $_POST['token'] || $_SESSION['expire'] < time()
|| $_SESSION['visitid'] != $_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT'] ) {
session_destroy(); // (invalid) clear session's variables, you could also kill session/cookie
exit (json_encode(array('status'=>'blocked'))); // exit an object that can be understood by your JS
}
Assumes standard session ini settings. Cookies required and page/relay on same domain (workround possible). Sessions might impact performance. If site already uses Sessions, code will need to take this into account.
2: Sessionless/Cookieless option
Uses a token associated with specific IP Address and User Agent, valid for a maximum of 2 hours.
Functions used by both page and relay e.g. "site-functions.inc":
Relay Script Use an existing example and before the CURL block add:
// assign post variable 'token' to $token
include '/pathTo/' . 'site-functions.inc';
$result = array('status'=>'timed out (try reloading) or invalid request');
if ( ! isValidToken($token)) exit(json_encode(array('msg'=>'invalid/timeout'))); // in format for handling by your JS
Pages needing the API (or your javascript include file):
...
// example Javascript with PHP insertion of token value
var dataString = existingDataString + "&token=" + ""
jQuery.ajax({type:"POST", url:"/whatever/myrelay.php",data: dataString, success: function(data){myOutput(data);} });
Note: User Agent is spoofable. IP (REMOTE_ADDR) "cannot" be faked but setup on a minority of sites can cause issues e.g. if you are behind NGINX you may find REMOTE_ADDR always contains the NGINX server IP.
If you are using a typical 3rd party API that will provide NON sensitive information until you reach the usage cap for your API Key then (I think) above solutions should be sufficient.