v2.x
The following examples are unique for branch 2.x of the API. UDP broadcast remains unchanged.
Authentication link
Node JS link
Node v16.14.0
const crypto = require('crypto')
const http = require('http')
function makeAuthorizationHeader(timestamp, hash) {
return `Samport-Keyed-Hash-v1 ${timestamp} ${hash}`
}
function generateRequestHash(secretKey, timestamp, httpMethod, httpPath, httpContent) {
const hashInput = `${secretKey}\n${timestamp}\n${httpMethod}\n${httpPath}\n${httpContent}\n${secretKey}`
return crypto.createHash('sha256').update(hashInput, 'utf8').digest('base64')
}
function generateResponseHash(secretKey, timestamp, httpMethod, httpPath, httpStatus, httpContent) {
const hashInput = `${secretKey}\n${timestamp}\n${httpMethod}\n${httpPath}\n${httpStatus}\n${httpContent}\n${secretKey}`
console.info('Hash input: ' + hashInput)
return crypto.createHash('sha256').update(hashInput, 'utf8').digest('base64')
}
const terminalIp = '12.232.12.31'
const terminalPort = 8080
const integrationKey = 'ABCDABCDABCDABCD'
const secretKey = 'HelloWorld'
const timestamp = new Date().toISOString()
const httpVerb = 'POST'
const httpPath = '/api/v2/Payments'
const content = JSON.stringify({
"amounts": {
"currencySymbol": "SEK",
"base": 10050
}
})
const options = {
host: terminalIp,
port: terminalPort,
path: httpPath,
method: httpVerb,
headers: {
'Integration-Key': integrationKey,
'Content-Type': 'application/json',
'Authorization': makeAuthorizationHeader(timestamp, generateRequestHash(secretKey, timestamp, httpVerb, httpPath, content))
}
}
const req = http.request(options, function(response) {
let data = ""
response.on('data', function(chunk) {
data += chunk
})
response.on('end', function() {
const serverAuthorization = response.headers['server-authorization']
const serverTimestamp = serverAuthorization.split(' ')[1]
const serverHash = serverAuthorization.split(' ')[2]
const correctHash = generateResponseHash(secretKey, serverTimestamp, httpVerb, httpPath, response.statusCode, data)
console.info('Status: ', response.statusCode)
console.info('Headers: ', response.headers)
console.info('Content: ' + data)
console.info('Server timestamp: ' + serverTimestamp)
console.info('Server hash: ' + serverHash)
console.info('Correct hash: ' + correctHash)
if (serverHash === correctHash) {
console.info('Response verified')
} else {
console.info('Response invalid')
}
})
})
req.write(content)
req.end()
Kotlin link
Kotlin 1.6.21
import com.google.gson.Gson
import java.net.HttpURLConnection
import java.net.URL
import java.nio.charset.Charset
import java.security.MessageDigest
import java.time.Instant
import java.util.*
const val terminalIp = "12.232.12.31"
const val terminalPort = 8080
const val integrationKey = "2870736033170FD5"
const val secretKey = "HelloWorld"
const val httpVerb = "POST"
const val httpPath = "/api/v2/Payments"
val timestamp = Instant.now().toString()
fun main() {
sendRequest()
}
fun sendRequest() {
val content = mapOf(
"amounts" to mapOf(
"currencySymbol" to "SEK",
"base" to 10050
)
)
val jsonContent = Gson().toJson(content)
val url = URL("http://$terminalIp:$terminalPort$httpPath")
val urlConnection = url.openConnection() as HttpURLConnection
urlConnection.setRequestProperty("Integration-Key", integrationKey)
urlConnection.setRequestProperty("Content-Type", "application/json")
urlConnection.setRequestProperty("Authorization", makeAuthorizationHeader(timestamp,generateRequestHash(secretKey,timestamp,httpVerb,httpPath, jsonContent)))
urlConnection.requestMethod = httpVerb
urlConnection.doOutput = true
urlConnection.outputStream.use { it.write(jsonContent.toByteArray(Charset.defaultCharset())) }
val responseCode = urlConnection.responseCode
println("Response Code: $responseCode")
val serverAuthorization = urlConnection.getHeaderField("server-authorization")
val serverAuthorizationSplit = serverAuthorization.split(" ")
val serverTimestamp = serverAuthorizationSplit[1]
val responseJson = urlConnection.inputStream.bufferedReader().use { it.readText() }
val correctHash = generateResponseHash(secretKey, serverTimestamp, httpVerb, httpPath, responseCode.toString(), responseJson)
val serverHash = serverAuthorizationSplit[2]
println(
"Parameters:\n " +
"SecretKey: $secretKey\n " +
"ServerTimestamp $serverTimestamp\n " +
"Httpverb: $httpVerb\n " +
"HttpPath: $httpPath\n " +
"Statuscode: $responseCode\n " +
"JSON: $responseJson\n\n " +
"CorrectHash: $correctHash\n"
)
if (serverHash == correctHash)
{
println("Response verified");
}
else
{
println("Response invalid");
}
println("*".repeat(80))
}
fun makeAuthorizationHeader(timestamp: String, hash: String): String {
return "Samport-Keyed-Hash-v1 $timestamp $hash"
}
fun generateRequestHash(secretKey: String, timestamp: String, httpMethod: String, httpPath: String, httpContent: String): String {
val hashInput = "$secretKey\n$timestamp\n$httpMethod\n$httpPath\n$httpContent\n$secretKey"
val bytes = hashInput.toByteArray()
val hash = MessageDigest.getInstance("SHA-256").digest(bytes)
return Base64.getEncoder().encodeToString(hash)
}
fun generateResponseHash(secretKey: String, timestamp: String, httpMethod: String, httpPath: String, httpStatus: String, httpContent: String): String {
val hashInput = "$secretKey\n$timestamp\n$httpMethod\n$httpPath\n$httpStatus\n$httpContent\n$secretKey"
val bytes = hashInput.toByteArray()
val hash = MessageDigest.getInstance("SHA-256").digest(bytes)
return Base64.getEncoder().encodeToString(hash)
}
C# link
.NET 7
using System.Security.Cryptography;
using System.Text;
using System.Globalization;
using System.Net;
using Newtonsoft.Json;
using System.Net.Http;
using System;
private const string terminalIp = "12.232.12.31";
private const int terminalPort = 8080;
private const string integrationKey = "2870736033170FD5";
private const string secretKey = "HelloWorld";
private const string httpVerb = "POST";
private const string httpPath = "/api/v2/Payments";
private static string timestamp = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffZ", CultureInfo.InvariantCulture);
public async Task SendRequest()
{
var content = new
{
amounts = new
{
currencySymbol = "SEK",
@base = 10050
}
};
var jsonContent = JsonConvert.SerializeObject(content);
var headers = new WebHeaderCollection
{
{"Integration-Key", integrationKey },
{"Content-Type", "application/json" },
{"Authorization", MakeAuthorizationHeader(timestamp, RequestHash(secretKey, timestamp, httpVerb, httpPath, jsonContent))}
};
string url = $"http://12.232.12.31:8080/api/v2/Payments";
using (var client = new HttpClient())
{
var request = new HttpRequestMessage
{
RequestUri = new Uri(url),
Method = HttpMethod.Post,
Content = new StringContent(jsonContent, Encoding.UTF8, "application/json")
};
foreach (string key in headers.AllKeys)
{
request.Headers.TryAddWithoutValidation(key, headers[key]);
}
var response = client.SendAsync(request).Result;
Console.WriteLine("### RESPONSE ###");
if (response.Headers.Contains("server-authorization"))
{
string serverAuthorization = response.Headers.GetValues("server-authorization").First();
string[] serverAuthorizationSplit = serverAuthorization.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
string serverTimestamp = serverAuthorizationSplit[1];
string serverHash = serverAuthorizationSplit[2];
string responseJson = await response.Content.ReadAsStringAsync();
string correctHash = ResponseHash(secretKey, serverTimestamp, httpVerb, httpPath, ((int)response.StatusCode).ToString(), responseJson);
Console.WriteLine($"Parameters:\n " +
$"SecretKey: {secretKey}\n " +
$"ServerTimestamp {serverTimestamp}\n " +
$"Httpverb: {httpVerb}\n " +
$"HttpPath: {httpPath}\n " +
$"Statuscode: {response.StatusCode}\n " +
$"JSON: {responseJson}\n\n " +
$"ServerHash: {serverHash} \n " +
$"CorrectHash: {correctHash}\n");
if (serverHash == correctHash)
{
Console.WriteLine("Response verified");
}
else
{
Console.WriteLine("Response invalid");
}
}
else
{
Console.WriteLine("Auth header is not present");
}
Console.WriteLine(new string('*', 80));
}
/*
* Combining the secretKey and parameters to create the header
* The spaces between the elements are necessary.
*/
static string MakeAuthorizationHeader(string timestamp, string hash)
{
return $"Samport-Keyed-Hash-v1 {timestamp} {hash}";
}
/*
* Combine the parameters to create the hashInput
* Create a byte array of the input
* Hash the byte array
* Base64 convert the hash
*/
static string RequestHash(string secretKey, string timestamp, string httpMethod, string httpPath, string httpContent)
{
string hashInput = $"{secretKey}\n{timestamp}\n{httpMethod}\n{httpPath}\n{httpContent}\n{secretKey}";
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(hashInput);
byte[] hash = SHA256.HashData(bytes);
return Convert.ToBase64String(hash);
}
static string ResponseHash(string secretKey, string timestamp, string httpMethod, string httpPath, string httpStatus, string httpContent)
{
string hashInput = $"{secretKey}\n{timestamp}\n{httpMethod}\n{httpPath}\n{httpStatus}\n{httpContent}\n{secretKey}";
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(hashInput);
byte[] hash = SHA256.HashData(bytes);
return Convert.ToBase64String(hash);
}
}
Python link
Python 3.11.5 and requests 2.31.0
import sys
import requests
import json
import base64
from hashlib import sha256
from datetime import datetime, timezone
def generateRequestHash(secretKey, timestamp, httpVerb, httpPath, httpContent):
# secretKey is added both in the beginning and the end to combat known sha256 vulnerability
hashInput = f"{secretKey}\n{timestamp}\n{httpVerb}\n{httpPath}\n{httpContent}\n{secretKey}"
return base64.b64encode(sha256(hashInput.encode("utf-8")).digest()).decode("utf-8")
def generateResponseHash(secretKey, timestamp, httpVerb, httpPath, httpStatus, httpContent):
#Authenticating the response is not mandatory but recommended. Note that the response also includes httpStatus
hashInput = f"{secretKey}\n{timestamp}\n{httpVerb}\n{httpPath}\n{httpStatus}\n{httpContent}\n{secretKey}"
return base64.b64encode(sha256(hashInput.encode("utf-8")).digest()).decode("utf-8")
# Setup
host = "http://12.232.12.31:8080" # Make sure this IP/PORT matches your device.
integrationkey = "Your IntegrationKey" # Distributed by Worldline integration team
secretkey = "HelloWorld" # Distributed by Worldline integration team
#timestamp in UTC to not be affected by DST
timestamp = datetime.now(timezone.utc).strftime('%Y-%m-%dT%H:%M:%S.%f')[:-3] + 'Z'
httpverb = "POST"
httppath = "/api/v2/Payments"
payload = json.dumps({
'amounts': {
'currencySymbol': 'SEK',
'base': 10050
}
})
authorizationheader = generateRequestHash(secretkey, timestamp, httpverb, httppath, payload)
headers = {'content-type': 'application/json; charset=utf-8',
'Integration-Key': integrationkey,
'User-Agent' : 'MyECR 1.0',
'Content-Length': str(len(payload)),
'Authorization' : f"Samport-Keyed-Hash-v1 {timestamp} {authorizationheader}"
}
#print("\n #Request Headers:\n"+ json.dumps(headers))
try:
req = requests.post(host + httppath, headers=headers, data=payload)
print(req.status_code, req.reason)
print(json.dumps(req.content.decode('utf-8'), indent=4))
except Exception as e:
raise e