Authentication (HMAC)

Tip

The authentication is already implemented in the API clients (SDKs).

HMAC-based authentication is the single preferred way of authentication to Recombee APIs.

Thanks to the nature of our APIs, authentication can reuse simple shared-secret approach with signature generated according to the HMAC-SHA1 standard. To be able to use HMAC based auth, you will need a secret key from Recombee. key needs to remain secret and known only to you and Recombee.

There are two params you need to attach to every API call:
  • hmac_timestamp,
  • hmac_sign,

where hmac_timestamp is a current UTC unix timestamp (integer). hmac_sign is signature computed from your request URI without protocol and host.

Every signature has limited lifetime (currently 10s). Therefore it is important that you have your server time synchronized via ntp or other source of precise time.

For example you want to make a call to the following URL

http://rapi.recombee.com/recombee/items/9346/recomms/?count=5&targetUserId=fb2fbe12-9f69-45a1-9fc0-df0c1592e4c7

Initial input to the signing method does not contain protocol and host parts. And the hmac_timestamp is added:

/recombee/items/9346/recomms/?count=5&targetUserId=fb2fbe12-9f69-45a1-9fc0-df0c1592e4c7&hmac_timestamp=1396859079

you sign this and finally append the signature:

/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 hash these strings and verify the results.

KEY = "gahpiev6eighaig1aek4ujietheiXeengae3Ohqu9iecutheof5rooxeigheel8G"
String Hash
Hello world 1291b164d8332792233dcc8ce94e1c9ea6113fb8
/recombee/items/9346/recomms/?count=5&targetUserId=fb2fbe12-9f69-45a1-9fc0-df0c1592e4c7&hmac_timestamp=1398463889 090eafba456488622a6d6f0dc37d3a1508536338

During implementation you only need to hash the address with the hmac_timestamp, without domain or protocol:

Right hash string:

/recombee/items/9346/recomms/?count=5
&targetUserId=fb2fbe12-9f69-45a1-9fc0-df0c1592e4c7
&hmac_timestamp=1398463889

Wrong hash string:

https://rapi.recombee.com/recombee/items/9346/recomms/?count=5
&targetUserId=fb2fbe12-9f69-45a1-9fc0-df0c1592e4c7
&hmac_timestamp=1398463889

Example Client Implementations

Description itself can be a bit cumbersome, but the actual implementations are very simple and straightforward.

Javascript

Using sha1.js from jsSHA. Please note that due to security reasons the requests to Recombee should be always sent from the server side (backend).

<head>
<script type="text/javascript" src="sha1.js"></script>
</head>

<body>
<script type="text/javascript">

  var key = "gahpiev6eighaig1aek4ujietheiXeengae3Ohqu9iecutheof5rooxeigheel8G";
  var url = "/recombee/items/9346/recomms/?count=5&targetUserId=fb2fbe12-9f69-45a1-9fc0-df0c1592e4c7";
  url = url + (url.indexOf("?") == -1 ? "?" : "&" ) + "hmac_timestamp=" + parseInt(new Date().getTime() / 1000);

  var shaObj = new jsSHA("SHA-1", "TEXT");
  shaObj.setHMACKey(key, "TEXT");
  shaObj.update(url);

  url = url + "&hmac_sign=" + shaObj.getHMAC("HEX");

  document.write(url);

</script>
</body>

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;
?>

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))

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);