Authentication (HMAC)
HMAC-based authentication is the single preferred way of authentication to Recombee APIs.
Thanks to the nature of our APIs, our authentication is based on a simple shared-secret approach with the signature generated according to the HMAC-SHA1 standard. To use HMAC-based authentication, you will need a token, which you can obtain in the Recombee Admin UI.
In the case of a server-side implementation, use the Private Token (which needs to remain secret and known only to you and Recombee), and in the case of a client-side implementation (e.g. in a mobile app), use the Public Token (see this section for details).
There are two parameters that you need to attach to every API call:
hmac_timestamp
- the current UTC Unix timestamp (integer)hmac_sign
- the signature computed from your request URI without protocol and host
Every signature has a limited lifetime (currently 10s). It is therefore important for your server time to be synchronized via NTP or other source of precise time.
For example, let's consider a call to the following URL:
http://rapi.recombee.com/recombee/items/9346/recomms/?count=5&targetUserId=fb2fbe12-9f69-45a1-9fc0-df0c1592e4c7
The initial input to the signing method does not contain the protocol and host
parts. We'll also add the hmac_timestamp
parameter:
/recombee/items/9346/recomms/?count=5&targetUserId=fb2fbe12-9f69-45a1-9fc0-df0c1592e4c7&hmac_timestamp=1396859079
We then compute the signature of the above string and append it as the hmac_sign
parameter. The result should then look like this:
/recombee/items/9346/recomms/?count=5&targetUserId=fb2fbe12-9f69-45a1-9fc0-df0c1592e4c7&hmac_timestamp=1396859079&hmac_sign=c608b597456d0760aee0e5a95017c63a8a24b4eb
Hash examples
To see whether you are hashing properly, you can try to hash the following strings and verify the results:
TOKEN = "gahpiev6eighaig1aek4ujietheiXeengae3Ohqu9iecutheof5rooxeigheel8G"
String | Hash |
---|---|
Hello world | 1291b164d8332792233dcc8ce94e1c9ea6113fb8 |
/recombee/items/9346/recomms/?count=5&targetUserId=fb2fbe12-9f69-45a1-9fc0-df0c1592e4c7&hmac_timestamp=1398463889 | 090eafba456488622a6d6f0dc37d3a1508536338 |
As mentioned above, the hash is calculated from the URL with the
hmac_timestamp
and without the domain or protocol.
Example of a correct hash string:
/recombee/items/9346/recomms/?count=5
&targetUserId=fb2fbe12-9f69-45a1-9fc0-df0c1592e4c7
&hmac_timestamp=1398463889
Example of an incorrect hash string:
https://rapi.recombee.com/recombee/items/9346/recomms/?count=5
&targetUserId=fb2fbe12-9f69-45a1-9fc0-df0c1592e4c7
&hmac_timestamp=1398463889
Authentication of Client-Side Requests
The same authentication method is used also for client-side (frontend) requests.
The differences are as follows:
- The Public Token is used for signing,
- The parameters have different names - use
frontend_timestamp
instead ofhmac_timestamp
andfrontend_sign
instead ofhmac_sign
, - The RAPI endpoint is at
client-rapi.recombee.com
.
See this example.
Postman
If you want to call the Recombee API using Postman, you can use the following script to authenticate your requests: https://github.com/Pazekal90/recombee-SHA1-HMAC-Postman-Pre-request-Script.
Example Implementations
The description itself can be a bit cumbersome, but the actual implementations are very simple and straightforward:
Python
import time
import hmac
from hashlib import sha1
key = 'gahpiev6eighaig1aek4ujietheiXeengae3Ohqu9iecutheof5rooxeigheel8G'
url = '/recombee/items/9346/recomms/?count=5&targetUserId=fb2fbe12-9f69-45a1-9fc0-df0c1592e4c7'\
'&hmac_timestamp=%s' % int(time.time())
sign = hmac.new(str.encode(key), str.encode(url), sha1).hexdigest()
print('%s&hmac_sign=%s' % (url, sign))
Ruby
require 'securerandom'
require 'digest/hmac'
KEY = "gahpiev6eighaig1aek4ujietheiXeengae3Ohqu9iecutheof5rooxeigheel8G"
url = '/recombee/items/9346/recomms/?count=5&targetUserId=fb2fbe12-9f69-45a1-9fc0-df0c1592e4c7' +
"&hmac_timestamp=#{Time.now.utc.to_i}"
sign = Digest::HMAC.hexdigest(url, KEY, Digest::SHA1)
puts "#{url}&hmac_sign=#{sign}"
PHP
<?php
$key = 'gahpiev6eighaig1aek4ujietheiXeengae3Ohqu9iecutheof5rooxeigheel8G';
$url = '/recombee/items/9346/recomms/?count=5&targetUserId=fb2fbe12-9f69-45a1-9fc0-df0c1592e4c7';
$url = $url . '&hmac_timestamp=' . time();
$sign = hash_hmac("sha1", $url, $key);
echo $url . "&hmac_sign=" . $sign;
?>
Java
import org.apache.commons.codec.binary.Hex;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
String key = "gahpiev6eighaig1aek4ujietheiXeengae3Ohqu9iecutheof5rooxeigheel8G";
String url = "/recombee/items/9346/recomms/?count=5&targetUserId=fb2fbe12-9f69-45a1-9fc0-df0c1592e4c7"+
"&hmac_timestamp="+System.currentTimeMillis() / 1000;
Mac mac = Mac.getInstance("HmacSHA1");
SecretKeySpec secret = new SecretKeySpec(key.getBytes(),"HmacSHA1");
mac.init(secret);
byte[] rawHmac = mac.doFinal(url.getBytes());
String sign = Hex.encodeHexString(rawHmac);
System.out.println(url+"&hmac_sign="+sign);
JavaScript
Using sha1.js
from jsSHA.
<head>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/jsSHA/2.4.2/sha.js"
integrity="sha512-aNuJL9dGmxptdarUqHqErH4MhgsJR0exQrlTRvCWWfZVwtB8El4iHpr6v+1ftov/7RAczXGCTDQQteAEaOzj6w=="
crossorigin="anonymous"
></script>
</head>
<body>
<script type="text/javascript">
const key = 'gahpiev6eighaig1aek4ujietheiXeengae3Ohqu9iecutheof5rooxeigheel8G';
let url =
'/recombee/items/9346/recomms/?count=5&targetUserId=fb2fbe12-9f69-45a1-9fc0-df0c1592e4c7';
url =
url +
(url.indexOf('?') == -1 ? '?' : '&') +
'frontend_timestamp=' +
parseInt(new Date().getTime() / 1000);
const shaObj = new jsSHA('SHA-1', 'TEXT');
shaObj.setHMACKey(key, 'TEXT');
shaObj.update(url);
url = url + '&frontend_sign=' + shaObj.getHMAC('HEX');
document.write(url);
</script>
</body>