This page is for in-depth technical information about the CX API. For a higher level overview, check out the Auth Service page.

PrivakeyCX supports two methods for authenticating API calls from Request Origins: HMAC and Basic. We recommend using HMAC as your authentication method; HMAC does not transfer the secret over the wire, so it is inherently more secure than Basic. Each Request Origin must be configured to use one of those methods. For more information on configuring Request Origins, see the Administration Section.

1. HMAC Authentication

HMAC is a method of generating a signature using well defined steps, which is then sent to the server along with the request. The generation steps are repeated on the server, and the signature sent with the request and the signature generated on the server are then compared. If identical, authentication has succeeded.

PrivakeyCX's HMAC authentication is comprised of several pieces: the algorithm version, the Request Origin's GUID, the milliseconds since the epoch, and the signature of the HMAC itself, combined in a certain order. Currently, the only algorithm supported is "CX1-HMAC-SHA256." The Request Origin's GUID and secret used to generate the signature are displayed and stored in PrivakeyCX's database at the time of Request Origin configuration.

It is combined in the following way and placed in the Authorization Header:

[algorithm],[RequestOriginGUID]/[millisecondsSinceEpoch],[base64Signature]

An example HMAC authorization header would be:

Authorization: CX1-HMAC-SHA256,306e8e0e-ee83-4bff-b1ff-8847931d83ec/1547654144951,ec9vkJcJFfSfdXXdwdglqP113Ov1F9S2BjhLxMsLHQo=

Please note the separators "," and "/".

HMAC Signatures

The signature is a base64 string generated using the secret key and certain data depending on whether a GET is used, or anything else with a postbody.

GET Signatures

If a GET method is being called, the signature is generated from signing a string concatenated with no separators using the supplied algorithm from the following:

  1. GET
  2. the full URI including protocols and paths of the route being called
  3. milliseconds since epoch
  4. the Request Origin's GUID

For example, calling the Get All Requests route on a CX server hosted at https://cx.privakey.com, with Request Origin GUID 306e8e0e-ee83-4bff-b1ff-8847931d83ec, and account id 1000, the signature could be generated like so:

// Nodejs
let dataToSign = 'GET' + 'https://cx.privakey.com/api/request/getAll?accountId=1000' + millisecondsFromEpoch + '306e8e0e-ee83-4bff-b1ff-8847931d83ec';
let hmac = crypto.createHmac('SHA256', secretKey); 
hmac.update(dataToSign);
let signature = hmac.digest('base64');

Non-GET Signatures (POST, PUT, etc.)

If any other method than GET is used, the postbody must also be included last while signing. For example, when adding a simple request:

  1. The method, e.g. POST or PUT
  2. the full URI including protocols and paths of the route being called
  3. milliseconds since epoch
  4. the Request Origin's GUID
  5. the post body as a string
// Nodejs
let postBody = '{"accountId":"1000", "notificationTitle":"A simple request", "notificationBody":"Do you approve the transaction?"}';
let dataToSign = 'POST' + 'https://cx.privakey.com/api/request/add' + millisecondsFromEpoch + '306e8e0e-ee83-4bff-b1ff-8847931d83ec' + postBody;
let hmac = crypto.createHmac('SHA256', secretKey); 
hmac.update(dataToSign);
let signature = hmac.digest('base64');

📘

Accepted Content-Types

All calls that send data in the body of the request can pass it either as application/json or as application/x-www-form-urlencoded.

HMAC JSON Canonicalization

JSON key/value pairs are, by specification, in no particular order. The order in which key/values are fed to the generation of the signature, however, DOES matter.

JSON such as

{"accountId":"1000", "notificationTitle":"A simple request","notificationBody":"Do you approve the transaction?"}

is considered equivalent to

{"notificationBody":"Do you approve the transaction?","notificationTitle":"A simple request", "accountId":"1000"}

but will generate a different signature.

PrivakeyCX will generate a signature from the postbody in the order that the key/values are transferred. This means using the first example above, PrivakeyCX will generate the signature from the postbody starting with accountId, and likewise using the second example, starting with notificationBody.

Because many JSON libraries follow spec, they may convert objects into JSON with an undeterministic order. Additional work may be required on the client end to sort the JSON keys, depending on the library you use. If the order in which keys are sorted when generating the signature does not match the order in which they are transferred as the postbody of the request, the comparision signature generated on PrivakeyCX will not match and the request will return a 401 Unauthorized.

❗️

White Space

When the Auth Service generates a signature based on the incoming request, it strips out any white space that is not in a key or value. Be sure to do the same on the client side, or the signatures will not match!

2. Basic Authentication

Basic HTTP Authentication is simple. Just follow these steps:

  1. Combine your Request Origin GUID and Secret with a single colon (:) between them.
  2. Base64-encode the result from step 1.
  3. Add the following header to your request: "Authorization: Basic <result from step 2>".

Here's an example, assuming your ID is "306e8e0e-ee83-4bff-b1ff-8847931d83ec" and your Secret is "abc123":

  1. Combined: "306e8e0e-ee83-4bff-b1ff-8847931d83ec:abc123"
  2. Base64 Encoded: "MzA2ZThlMGUtZWU4My00YmZmLWIxZmYtODg0NzkzMWQ4M2VjOmFiYzEyMw=="
  3. Header to Add: Authorization: Basic MzA2ZThlMGUtZWU4My00YmZmLWIxZmYtODg0NzkzMWQ4M2VjOmFiYzEyMw==