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' })