HMACSHA256 Authentication¶
Introduction¶
The HMAC stands for Hash-based Message Authentication Code. It involves two key ideas: Message Authentication Code and Hash-Based processing. HMAC is a mechanism to create a Message Authentication Code using a Hash function.
For generating the Message Authentication Code using a Hash function, a Shared Secret Key is used. This Shared Secret Key must be securely shared between the Client and the Server.
Keys Used in HMAC Authentication in Web API¶
The server (Mobilum) generates two keys: - API Key (already provided to the partner) - Private Secret Key
These keys must be provided to the Partner securely (e.g., via email).
Once the Partner obtains the private secret key, they must generate a unique HMAC signature (hash) containing both the request data and necessary metadata for the server to process the request.
The HMAC Flow¶
The Partner creates a MAC (Message Authentication Code) string containing:
API Key
HTTP method (POST)
Request URI (lowercased)
Request timestamp (UTC Now)
Nonce
Request URI: Must be in lowercase.
Request Timestamp: Calculated using UNIX time (seconds since Jan 1, 1970).
Nonce: Random string (using a GUID), unique per request.
Example URI:
https://api.mobilum.com/s2s/health?arg1=test1
The Partner then generates a HASH (unique signature) using the SHA256 algorithm and the Private Secret Key.
Example signature construction:
var signatureRawData = "{ApiKey}{RequestHTTPMethod}{RequestUri}{RequestTimeStamp}{Nonce}"
Without braces:
16de9f8b-b414-4c50-b3c8-cf8355683a42POSThttps://api.mobilum.com/s2s/health?arg1=test1167474201375293d8ca0e6453f823fe87315e9483b“
Authorization Header Format:
Authorization: HMAC-SHA256 ApiKey:Signature:Nonce:Timestamp
Example:
Header Key: Authorization
Header Value: HMAC-SHA256 16de9f8b-b414-4c50-b3c8-cf8355683a42:mlf8nvpV2WQ2eOJpdKJ7g3Sl0an9Xhc4PlAzdMihJO8=:85b9ceacde384490825e3b2153bc7684:1674227388
HMAC Implementation Example in C#¶
using System.Net.Http.Headers;
using System.Security.Cryptography;
using System.Text;
using System.Web;
class Program
{
static void Main(string[] args)
{
RunAsync().Wait();
Console.ReadLine();
}
static async Task RunAsync()
{
Console.WriteLine("Calling the back-end API");
string apiBaseAddress = "https://api.mobilum.com/";
HMACDelegatingHandler customDelegatingHandler = new HMACDelegatingHandler();
HttpClient client = HttpClientFactory.Create(customDelegatingHandler);
HttpResponseMessage response = await client.PostAsJsonAsync(apiBaseAddress + "s2s/health");
if (response.IsSuccessStatusCode)
{
string responseString = await response.Content.ReadAsStringAsync();
Console.WriteLine(responseString);
Console.WriteLine("HTTP Status: {0}, Reason {1}. Press ENTER to exit", response.StatusCode, response.ReasonPhrase);
}
else
{
string responseString = await response.Content.ReadAsStringAsync();
Console.WriteLine("Failed to call the API. HTTP Status: {0}, Reason {1}", response.StatusCode, response.ReasonPhrase);
}
}
}
public class HMACDelegatingHandler : DelegatingHandler
{
private string ApiKey = "16de9f8b-b414-4c50-b3c8-cf8355683a42";
private string SecretKey = "HtDiRYMtBLmyq7snk2xvh3mO0PrO3HBxVWm85FaQ2CZ7eLqnYYG3gMYz9esmHx8I7m5LTQa5zVnGo3pM";
protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
try
{
HttpResponseMessage response = null;
string requestUri = request.RequestUri.AbsoluteUri.ToLower();
string requestHttpMethod = request.Method.Method;
DateTime epochStart = new DateTime(1970, 01, 01, 0, 0, 0, 0, DateTimeKind.Utc);
TimeSpan timeSpan = DateTime.UtcNow - epochStart;
string requestTimeStamp = Convert.ToUInt64(timeSpan.TotalSeconds).ToString();
string nonce = Guid.NewGuid().ToString("N");
string signatureRawData = String.Format("{0}{1}{2}{3}{4}", ApiKey, requestHttpMethod, requestUri, requestTimeStamp, nonce);
var secretKeyByteArray = Convert.FromBase64String(SecretKey);
byte[] signature = Encoding.UTF8.GetBytes(signatureRawData);
using (HMACSHA256 hmac = new HMACSHA256(secretKeyByteArray))
{
byte[] signatureBytes = hmac.ComputeHash(signature);
string requestSignatureBase64String = Convert.ToBase64String(signatureBytes);
request.Headers.Authorization = new AuthenticationHeaderValue("HMAC-SHA256", string.Format("{0}:{1}:{2}:{3}", ApiKey, requestSignatureBase64String, nonce, requestTimeStamp));
}
request.Headers.Add("apikey", ApiKey);
response = await base.SendAsync(request, cancellationToken);
return response;
}
catch (HttpRequestException ex)
{
return null;
}
}
}
HMAC Implementation Example in PHP¶
<?php
include 'phpseclib3/Crypt/Hash.php';
use phpseclib3\Crypt\Hash;
$ch = curl_init();
$baseUrl = 'https://api.mobilum.com/s2s/health';
$ApiKey = "d327d550-93ca-43f0-bdab-53782e181086";
$SecretKey = "HtDiRYMtBLmyq7snk2xvh3mO0PrO3HBxVWm85FaQ2CZ7eLqnYYG3gMYz9esmHx8I7m5LTQa5zVnGo3pM/D6YSQ==";
$requestTimeStamp = time();
$guid = "";
if (function_exists('com_create_guid')){
$guid = com_create_guid();
} else {
mt_srand((double)microtime()*10000);
$charid = strtoupper(md5(uniqid(rand(), true)));
$hyphen = chr(45);
$uuid = chr(123)
.substr($charid, 0, 8).$hyphen
.substr($charid, 8, 4).$hyphen
.substr($charid,12, 4).$hyphen
.substr($charid,16, 4).$hyphen
.substr($charid,20,12)
.chr(125);
$guid = $uuid;
}
$guid = trim($guid, "{}");
$url = strtolower('https://api.mobilum.com/s2s/health');
$method = 'POST';
$signatureRawData = $ApiKey . $method . $url . $requestTimeStamp . $guid;
$hmac = new Hash();
$hmac->setKey(base64_decode($SecretKey));
$signature = $hmac->hash($signatureRawData);
$serverSignature = base64_encode($signature);
$signatureHeader = sprintf("%s:%s:%s:%s", $ApiKey, $serverSignature, $guid, $requestTimeStamp);
curl_setopt($ch, CURLOPT_URL, $baseUrl);
$body = array();
$payload = json_encode($body);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type:application/json',
'ApiKey:' . $ApiKey,
'Authorization: HMAC-SHA256 ' . $signatureHeader
));
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$response = curl_exec($ch);
$result = json_decode($response);
curl_close($ch);
?>