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.
using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Security.Cryptography; using System.Net; using System.Web; // ... String entrypoint = "http://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); } } // Getting data as String: String timedata = servicecall("timeservice", new NameValueCollection {{"placeid", "norway/oslo"}, {"out", "js"}})
Requires third-party dependency axios.
const crypto = require('crypto'); // https://nodejs.org/api/crypto.html const axios = require("axios"); // const entrypoint = 'http://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); }))
use Digest::HMAC_SHA1; use LWP::Simple; use URI::Escape; use POSIX qw(strftime); sub servicecall($%); my ($entrypoint, $accesskey, $secretkey) = qw(http://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"); }
$entrypoint = 'http://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; }
import base64, datetime, hashlib, hmac, urllib entrypoint = "http://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'))
require 'base64' require 'cgi' require 'hmac-sha1' require 'net/http' $entrypoint = 'http://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' })