Interface for creating an API Key relation between a user and authentication key & secret
An overview of the API Keys created on the site
Configuration example of a REST end-point for basic node creation.

A basic approach to handling API keys, implemented to be used together with REST.

Using 4 different headers and a HMAC based approach to authenticate users, all POST, PATCH, DELETE, PUT requests can be authenticated – I have not attempted to do this using GET requests as those mostly have a tendency to be broken.

Notice that even though this is API Key based do not mean that the /session/token can be omitted.

1. Create an API key, selection who the key should authenticate as on the site.
Interface for creating an API Key relation between a user and authentication key & secret
2. Enable a REST end-point with the api_key_auth as the authenticator.
An overview of the API Keys created on the site
3. Call the REST endpoint using a HMAC based authentication signature.
Configuration example of a REST end-point for basic node creation
4. Use a client to create a node. (I used the basic article node from the standard profile for this)
I used the following request to verify that it works. Notice that the x-auth headers are used by this module.

  • iss: Issuer of the request, this is the API-Key which is autogenerated by the module.
  • exp: Expire timestamp, if there is a timeframe for latest execution of this request.
  • nbf: Not-before – request should not be executed before the given timestamp, will be ignored if in the future. (potential future improvement would be a queue system that handles the request in the future)
  • signature: A signature created specifically for this one request, see how it is calculated below.
curl -X POST \
  'http://drupal.docker.localhost:8001/entity/node?_format=hal_json' \
  -H 'cache-control: no-cache' \
  -H 'content-type: application/hal+json' \
  -H 'x-auth-exp: 15105640975' \
  -H 'x-auth-iss: M-LmI2b3pA0UdIuU7OhXEw' \
  -H 'x-auth-nbf: 1510564092' \
  -H 'x-auth-signature: dBKHsgW0zAT2uopxF1V6p750160fuYB+D6h/zTNwXU4=' \
  -H 'x-csrf-token: dJZzj4qC-_I88x6HmJPUZKXXMO-6diNEelttfoiOEXo' \
  -d '{
    "_links": {
        "type": {
            "href": "http://drupal.docker.localhost:8001/rest/type/node/article"
        },
        "http://drupal.docker.localhost:8001/rest/relation/node/article/uid": [
            {
                "href": "http://drupal.docker.localhost:8001/user/0?_format=hal_json",
                "lang": "en"
            }
        ],
        "http://drupal.docker.localhost:8001/rest/relation/node/article/revision_uid": [
            {
                "href": "http://drupal.docker.localhost:8001/user/0?_format=hal_json"
            }
        ]
    },
	"langcode": [
        {
            "value": "en",
            "lang": "en"
        }
    ],
    "type": [
        {
            "target_id": "article"
        }
    ],
    "title": [
        {
            "value": "Aesting article through rest",
            "lang": "en"
        }
    ],
    "body": [
        {
            "value": "Ad mos ratis vulpes. Comis decet interdico populus qui tamen vereor. Defui iriure macto patria plaga premo. Blandit caecus dolus jumentum nunc. Aptent dolore ideo incassum ludus secundum. Minim nulla rusticus vicis. Appellatio aptent cui eum luctus natu obruo odio populus virtus. Fere genitus gilvus lobortis macto persto plaga quia.\n\n",
            "format": "plain_text"
        }
    ]
}'

To calculate the Signature you should use a given payload, which identified this specific request – currently this is a concatenation of iss, exp, nbf and the post data.

var payload = apiKey + exp + nbf + requestBody;

I used the following approach to generating the signature in Postman (done in the Pre-request Script)

pm.sendRequest('{{url}}/session/token', function(err, res) {
    if (err) {
        console.log(err);
    }
    pm.environment.set("csrf-token", res.text());
});

function epochTime() {
    var d = new Date();
    var t = d.getTime();
    var o = t + "";
    return o.substring(0, 10);
}

var apiKey = pm.environment.get('auth-api-key');
var secret = pm.environment.get('auth-shared-secret');

// Allow for 5 seconds of execution time.
var exp = epochTime() + 5;
// Allow the request to have originated 5 seconds previous.
var nbf = epochTime() - 5;

var requestBody = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(request.data));
var payload = apiKey + exp + nbf + requestBody;
var signature = CryptoJS.HmacSHA256(payload, secret);

console.log(signature);

pm.environment.set('auth-exp', exp);
pm.environment.set('auth-nbf', nbf);
pm.environment.set('auth-signature', signature.toString(CryptoJS.enc.Base64));

The request headers used from Postman

Supporting organizations: 
Sponsored development time

Project information

Releases