Example code
-
Using a delegating handler you can separate the generation of the authorization header from the actual request.
using (var client = HttpClientFactory.Create(new HMacDelegatingHandler("your-appkey-id","your-appkey-secret"))) { var result = await client.GetAsync("https://api.combell.com/v1/domains"); // Do something with the result here. }
The delegating handler:
This implements the signature generation and sets the Authorization header.
public class HMacDelegatingHandler : DelegatingHandler { private string _appId; private string _appSecret; internal HMacDelegatingHandler(string appId, string appSecret) { _appId = appId; _appSecret = appSecret; } protected async override Task
SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { HttpResponseMessage response = null; var requestContentBase64String = string.Empty; // Calculate UNIX time var epochStart = new DateTime(1970, 01, 01, 0, 0, 0, 0, DateTimeKind.Utc); var timeSpan = DateTime.UtcNow - epochStart; var requestTimeStamp = Convert.ToUInt64(timeSpan.TotalSeconds).ToString(); // Create random nonce for each request var nonce = Guid.NewGuid().ToString("N"); // Check if the request contains body, usually will be null when request method is GET or DELETE if (request.Content != null) { var content = await request.Content.ReadAsByteArrayAsync(); using (var md5 = MD5.Create()) { // Hash the request body, any change in request body will result in different hash, we'll incure message integrity var requestContentHash = md5.ComputeHash(content); requestContentBase64String = Convert.ToBase64String(requestContentHash); } } // Generate the hashed signature var signatureData = String.Format("{0}{1}{2}{3}{4}{5}", _appId, request.Method.Method.ToLower(), WebUtility.UrlEncode(string.Format("{0}{1}", request.RequestUri.LocalPath, request.RequestUri.Query)), requestTimeStamp, nonce, requestContentBase64String); var encoding = Encoding.UTF8; var signatureBytes = encoding.GetBytes(signatureData); var secretKeyByteArray = encoding.GetBytes(_appSecret); using (var hmac = new HMACSHA256(secretKeyByteArray)) { var signatureHash = hmac.ComputeHash(signatureBytes); var requestSignatureBase64String = Convert.ToBase64String(signatureHash); // Set the values in the Authorization header using custom scheme (hmac) request.Headers.Authorization = new AuthenticationHeaderValue( "hmac", string.Format("{0}:{1}:{2}:{3}", _appId, requestSignatureBase64String, nonce, requestTimeStamp)); } response = await base.SendAsync(request, cancellationToken); return response; } } -
Use our PHP package to find examples of all API calls and a Guzzle handler to simplify authorization: https://github.com/combell/combell-api.
Reference guzzle in composer.json
{ "require": { "guzzlehttp/guzzle": "~6.0" } }
Using a delegating handler you can separate the generation of the authorization header from the actual request.
include('vendor/autoload.php'); include('HmacHandler.php'); $hmacHandler = new HmacHandler('your-apikey-id','your-apikey-secret'); $stack = \GuzzleHttp\HandlerStack::create(); $stack->push($hmacHandler); $client = new \GuzzleHttp\Client(['handler' => $stack, 'debug' => true]); $response = $client->get('https://api.combell.com/v1/domains');
The delegating handler:
This implements the signature generation and sets the Authorization header.
class HmacHandler { protected $apiKey; protected $apiSecret; public function __construct($apiKey, $apiSecret) { $this->apiKey = $apiKey; $this->apiSecret = $apiSecret; } protected function sign(Psr\Http\Message\RequestInterface $request) { $time = time(); $nonce = uniqid(); $path = (string) $request->getUri()->getPath(); $query = (string) $request->getUri()->getQuery(); $body = (string) $request->getBody()->getContents(); if ($query !== '') { $path .= '?' . $query; } if ($body !== '') { $body = base64_encode(md5($body, true)); } $valueToSign = $this->apiKey . strtolower($request->getMethod()) . urlencode($path) . $time . $nonce . $body; $signedValue = hash_hmac('sha256', $valueToSign, $this->apiSecret, true); $signature = base64_encode($signedValue); return sprintf('hmac %s:%s:%s:%s', $this->apiKey, $signature, $nonce, $time); } public function __invoke(callable $handler) { return function (Psr\Http\Message\RequestInterface $request, array $options) use ($handler) { $request = $request->withHeader('Authorization', $this->sign($request)); return $handler($request, $options); }; } }