HMAC Authentication
===================

Elgg's RESTful API framework provides functions to support a `HMAC`_ signature scheme for API authentication. The client must send 
the HMAC signature together with a set of special HTTP headers when making a call that requires API authentication. This ensures 
that the API call is being made from the stated client and that the data has not been tampered with.

.. _HMAC: https://en.wikipedia.org/wiki/HMAC

The HMAC must be constructed over the following data:

- The public API key identifying you to the Elgg api server as provided by the APIAdmin plugin
- The private API Key provided by Elgg (that is companion to the public key)
- The current unix time in seconds
- A nonce to guarantee two requests the same second have different signatures
- URL encoded string representation of any GET variable parameters, eg ``method=test.test&foo=bar``
- If you are sending post data, the hash of this data

Some extra information must be added to the HTTP header in order for this data to be correctly processed:

- **X-Elgg-apikey** - The public API key
- **X-Elgg-time** - Unix time used in the HMAC calculation
- **X-Elgg-nonce** - a random string
- **X-Elgg-hmac** - The HMAC as base64 encoded
- **X-Elgg-hmac-algo** - The algorithm used in the HMAC calculation

If you are sending POST data you must also send:

- **X-Elgg-posthash** - The hash of the POST data
- **X-Elgg-posthash-algo** - The algorithm used to produce the POST data hash
- **Content-type** - The content type of the data you are sending (this can be ``application/x-www-form-urlencoded`` or ``multipart/form-data``)
- **Content-Length** - The length in bytes of your POST data

Elgg provides a sample API client that implements this HMAC signature: ``\Elgg\WebServices\ElggApiClient``. It serves as a good 
reference on how to implement it.

Supported hashing algorithms
----------------------------

- ``sha256``: recommended
- ``sha1``: fast however less secure
- ``md5``: weak and will be removed in the future

POST hash calculation
---------------------

When sending the POST data as ``Content-Type: application/x-www-form-urlencoded;`` the post hash needs to be calculated
over all the post data using one of the supported hashing algorithms.

When sending the POST data as ``Content-Type: multipart/form-data;`` the post hash needs to be calculated
over an empty string.

The result of the hashing needs to be reported in the ``X-Elgg-posthash`` header and the used hashing algorithm must be
reported in the ``X-Elgg-posthash-algo`` header.

.. warning::

	Since the POST hash isn't calculated when using ``Content-Type: multipart/form-data;`` only use this when calling
	APIs that need an file input.

HMAC hash calculation
---------------------

The overall HMAC needs to be calculated over the following data (in order) using the API secret as the HMAC secret and with one
of the supported hashing algorithms:

1. a UNIX timestamp, report this timestamp in the ``X-Elgg-time`` header
2. a random string, report this string in the ``X-Elgg-nonce`` header
3. the public API key, report this API key in the ``X-Elgg-apikey`` header
4. the url query string (for example ``method=test.test&foo=bar``)
5. when the request is a POST add the ``posthash`` as reported in the ``X-Elgg-posthash`` header

The resulting string needs to be base64 encoded and then url encoded and be reported in the ``X-Elgg-hmac`` header.
The used hashing algorithm needs to be reported in the ``X-Elgg-hmac-algo``.

Hashing cache
-------------

For security reasons each HMAC hash needs to be unique, all submitted hashes are stored for 25 hours to prevent reuse.
