# Authentication (HMAC)

> Source: https://docs.recombee.com/authentication

> For the complete documentation index, see [llms.txt](/llms.txt).

**Table of contents**

* [Hash Examples](#hash-examples)
* [Authentication of Client-Side Requests](#authentication-of-client-side-requests)
* [Postman](#postman)
* [Example Implementations](#example-implementations)  
   * [Python](#python)  
   * [Ruby](#ruby)  
   * [PHP](#php)  
   * [Java](#java)  
   * [JavaScript](#javascript)

# Authentication (HMAC)

The authentication is already implemented in the [API clients (SDKs)](/api_clients).

**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](/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](#authentication-of-client-side-requests) for details).

**There are two query 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 30s). 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:

```
https://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 of`hmac_timestamp` and `frontend_sign` instead of `hmac_sign`,
* The RAPI endpoint is at `client-rapi.recombee.com`.

See [this example](#JavaScript-authentication-example).

## Postman

If you want to call the Recombee API using [Postman](https://www.postman.com/), 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

```
  $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](https://github.com/Caligatio/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>
```