General: Sample Implementations

Following is sample implementations for constructing and submitting an API request using HMAC authentication in some of the most popular programming languages. In these samples we use our timeservice as an example, the sample implementation is however applicable to all of our services.

C#/.NET


using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Security.Cryptography;
using System.Net;
using System.Web;
 
// ...
String entrypoint = "https://api.xmltime.com/";
String accesskey = "NYczonwTxv";
String secretkey = "x4whvXnG7cCOBiNBoi1r";

public String servicecall(String service, NameValueCollection iargs) {
    // Hash computation
    var timestamp = DateTime.UtcNow.ToString("o");
    var message = accesskey + service + timestamp;
    var hmac = new HMACSHA1(System.Text.Encoding.ASCII.GetBytes(secretkey));
    var hash = hmac.ComputeHash(System.Text.Encoding.ASCII.GetBytes(message));

    // Copy arguments and add authentication parameters
    var args = new NameValueCollection(iargs);
    args.Set("accesskey", accesskey);
    args.Set("timestamp", timestamp);
    args.Set("signature", Convert.ToBase64String(hash));

    // Generate URI from the arguments
    List<String> items = new List<String>();
    foreach (String key in args.AllKeys)
        items.Add(String.Concat(HttpUtility.UrlEncode(key), "=", HttpUtility.UrlEncode(args[key])));

    UriBuilder uri = new UriBuilder(entrypoint + service);
    uri.Query = String.Join("&", items.ToArray());

    // Retrieve data and return it
    using (WebClient client = new WebClient()) {
        client.Encoding = System.Text.Encoding.UTF8;
        return client.DownloadString(uri.Uri);
    }
}
    

JavaScript/Node.js

Note: Requires third-party dependency axios.

const crypto = require('crypto'); // https://nodejs.org/api/crypto.html
const axios = require("axios"); // 

const entrypoint = 'https://api.xmltime.com/';
const accesskey = 'NYczonwTxv';
const secretkey = 'x4whvXnG7cCOBiNBoi1r';

function servicecall(service, args) {
  const timestamp = new Date().toISOString();
  const message = `${accesskey}${service}${timestamp}`;
  const signature = crypto.createHmac('sha1', secretkey)
  .update(message)
  .digest('base64');
  Object.assign(args, {
    accesskey,
    timestamp,
    signature
  });

  const query = Object.keys(args)
  .map((key) => `${encodeURIComponent(key)}=${encodeURIComponent(args[key])}`)
  .join("&")

  const url = `${entrypoint}/${service}?${query}`
  return axios.get(url).then( (res) => res.data);
}

servicecall("timeservice", { "placeid": "norway/oslo", "out": "js", "version": 2} )
.then((res) => {
    console.log(JSON.stringify(res, null, 2));
})
.catch((e => {
    console.error(e);
}))
    

Perl


use Digest::HMAC_SHA1;
use LWP::Simple;
use URI::Escape;
use POSIX qw(strftime);

sub servicecall($%);

my ($entrypoint, $accesskey, $secretkey) =
    qw(https://api.xmltime.com/ NYczonwTxv x4whvXnG7cCOBiNBoi1r);

my $timedata = servicecall('timeservice', (placeid=>'norway/oslo', out=>'js');


sub servicecall($%) {
    my ($service, %args) = @_;
    my ($timestamp, $hmac, $signature, $query);

    $timestamp = strftime("%FT%T", gmtime());
    $hmac = Digest::HMAC_SHA1->new($secretkey);
    $hmac->add("$accesskey$service$timestamp");
    $signature = $hmac->b64digest;

    $args{accesskey} = $accesskey;
    $args{timestamp} = $timestamp;
    $args{signature} = $signature;

    $query = join(';', map { "$_=".uri_escape($args{$_}) } keys %args);

    return get("$entrypoint/$service?$query");
}
    

PHP


$entrypoint = 'https://api.xmltime.com/';
$accesskey = 'NYczonwTxv';
$secretkey = 'x4whvXnG7cCOBiNBoi1r';

$timedata = servicecall('timeservice', array('placeid'=>'norway/oslo'));

function servicecall($service, $args) {
    global $entrypoint, $accesskey, $secretkey;

    $timestamp = gmdate('c');
    $message = "$accesskey$service$timestamp";
    $signature = base64_encode(hash_hmac('sha1', $message, $secretkey, true));

    $args['accesskey'] = $accesskey;
    $args['timestamp'] = $timestamp;
    $args['signature'] = $signature;

    $url = "$entrypoint/$service?" . http_build_query($args);

    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
    $result = curl_exec($ch);
    curl_close($ch);
    return $result;
}
    

Python


import base64, datetime, hashlib, hmac, urllib

entrypoint = "https://api.xmltime.com/"
accesskey = "NYczonwTxv"
secretkey = "x4whvXnG7cCOBiNBoi1r"

def servicecall(service, args):
    global entrypoint, accesskey, secretkey

    timestamp = datetime.datetime.utcnow().isoformat()
    message = accesskey + service + timestamp
    digester = hmac.new(secretkey, message, hashlib.sha1)

    args['accesskey'] = accesskey
    args['timestamp'] = timestamp
    args['signature'] = base64.b64encode(digester.digest())

    url = entrypoint + '/' + service + '?' + urllib.urlencode(args)
    return urllib.urlopen(url).read()

timedata = servicecall("timeservice", dict(placeid=187, out='js'))
    

Ruby


require 'base64'
require 'cgi'
require 'hmac-sha1'
require 'net/http'

$entrypoint = 'https://api.xmltime.com/'
$accesskey = 'NYczonwTxv'
$secretkey = 'x4whvXnG7cCOBiNBoi1r'

def servicecall(service, args)
    timestamp = Time.now.getutc.strftime('%FT%T')
    message = $accesskey + service + timestamp
    digest = HMAC::SHA1.digest($secretkey, message)

    args['accesskey'] = $accesskey
    args['timestamp'] = timestamp
    args['signature'] = Base64.encode64(digest).chomp

    query = args.collect do |key, value|
        [key.to_s, CGI::escape(value.to_s)].join('=')
    end.join(';')

    url = $entrypoint + '/' + service + '?' + query
    Net::HTTP.get(URI.parse(url))
end

timedata = servicecall('timeservice', { 'placeid'=>187, 'out'=>'js' })