Here are some code samples to help you with your RSA Authentication method implementation. These examples are run on the Test endpoint .
#! /bin/bash
# Put your public key here, keep it on a single line
PUB_KEY="-----BEGIN RSA PUBLIC KEY-----MEgCQQCQyhMk37PWcf8Y/5jbjPxhMw/N35PwCasZUdWvhLWIHf6YqOuyo00Jtc7M0kj3/tybiWAZ1X3NSIvmTXJ5J2ctAgMBAAE=-----END RSA PUBLIC KEY-----"
# Put your private key here, with the line breaks
PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----
MIIBOwIBAAJBAJDKEyTfs9Zx/xj/SNuM/GEzD83fk/AJqx
lR1a+EtYgd/pio67KjTQm1zszSSPf+3JuJYBnVfc1Ii+ZN
cnknZy0CAwEAAQJADfghHraikDcRaKUAr4YLt4kIplFC4a
7dHiVCG5wPM6Gj6ghyribNRMXQS0/bsGmsxOsar7dh0Boh
9jLnec56gQIhANJSria/oKfEzdQKTdfMOM9D6Gw1Dd9RWE
L7yih+M1YhAiEAsDvskelGHt6CzK4vyJJabhUdD8vq+78w
ncN9G42kF40CIQC7nvQqLuIDJ4YxtKtyaYT4KG0LMlzYrX
kd7/2MF+B14QIhAKdkc8LwCPt/LEwP0zE22hAfm9gKP6tZ
IWtoaKfINKltAiAqEBbkEM2ZvmU+QMbF1hQxyRENZS0STO
Cy2X53gi/tRg==
-----END RSA PRIVATE KEY-----"
# Get the current UNIX timestamp and generate a random string
TIMESTAMP=$(date +%s)
NONCE=$(openssl rand -hex 8)
# Example body
# Remember to sort this JSON object by key in alphabetical order recursively
# in order to sign your request
BODY='{"testArray":["this","is","an","array"],"testBool":true,"testNumber":123,"testObject":{"a":true,"b":false},"testString":"hello"}'
# Example query params
# Remember to sort this JSON object by key in alphabetical order recursively
# in order to sign your request
QUERY_PARAMS='{"bar":"42","foo":"hi"}'
# JSON object to be signed
# Please respect the order or your signature won't be validated
TO_SIGN=$(printf '{"security":{"nonce":"%s","timestamp":"%s"},"queryParams":%s,"body":%s}' $NONCE $TIMESTAMP $QUERY_PARAMS $BODY)
# Generate the signature
SIGN=$(echo $TO_SIGN | tr -d '\\n' | openssl dgst -sha256 -sign <(echo "${PRIVATE_KEY}") | base64)
# Make the request
curl \\
-X POST \\
-d $BODY \\
'<https://api.e-potek.ch/api/test?foo=hi&bar=42>' \\
-H 'Content-Type: application/json' \\
-H "X-RESOLVE-Authorization: RESOLVE ${PUB_KEY}:${SIGN}" \\
-H "X-RESOLVE-Nonce: ${NONCE}" \\
-H "X-RESOLVE-Timestamp: ${TIMESTAMP}" \\
import https from "https";
import NodeRSA from "node-rsa";
import queryString from "query-string";
// Your API public key
const publicKey =
"-----BEGIN RSA PUBLIC KEY-----\\n" +
"MEgCQQCGZse2vDomKwX42nV3ZwJsbw/RGzbtCoz00xnciiHvJOGn\\n" +
"79MDLQ93aXJVJb0YwqwYIqQHqJI/I1/2inD353lnAgMBAAE=\\n" +
"-----END RSA PUBLIC KEY-----";
// Your API private key
const privateKey =
"-----BEGIN RSA PRIVATE KEY-----\\n" +
"MIIBOQIBAAJAVY6quuzCwyOWzymJ7C4zXjeV/232wt2ZgJZ1kHzjI73wnhQ3WQcL\\n" +
"DFCSoi2lPUW8/zspk0qWvPdtp6Jg5Lu7hwIDAQABAkBEws9mQahZ6r1mq2zEm3D/\\n" +
"VM9BpV//xtd6p/G+eRCYBT2qshGx42ucdgZCYJptFoW+HEx/jtzWe74yK6jGIkWJ\\n" +
"AiEAoNAMsPqwWwTyjDZCo9iKvfIQvd3MWnmtFmjiHoPtjx0CIQCIMypAEEkZuQUi\\n" +
"pMoreJrOlLJWdc0bfhzNAJjxsTv/8wIgQG0ZqI3GubBxu9rBOAM5EoA4VNjXVigJ\\n" +
"QEEk1jTkp8ECIQCHhsoq90mWM/p9L5cQzLDWkTYoPI49Ji+Iemi2T5MRqwIgQl07\\n" +
"Es+KCn25OKXR/FJ5fu6A6A+MptABL3r8SEjlpLc=\\n" +
"-----END RSA PRIVATE KEY-----";
// Sorts an object by key in alphabetical order recursively
const sortObject = object => {
if (!object || typeof object !== "object" || object instanceof Array) {
return object;
}
const sortedObject = {};
const keys = Object.keys(object);
keys.sort();
keys.forEach(key => {
sortedObject[key] = sortObject(object[key]);
});
return sortedObject;
};
// Signs you request with your private key
const signRequest = ({ body, query, timestamp, nonce, privateKey }) => {
const key = new NodeRSA();
key.importKey(privateKey.replace(/\\r?\\n|\\r/g, ""), "pkcs1-private-pem");
let objectToSign = { security: sortObject({ timestamp, nonce }) };
if (query) {
objectToSign = { ...objectToSign, queryParams: sortObject(query) };
}
if (body) {
objectToSign = { ...objectToSign, body: sortObject(body) };
}
const signature = key.sign(JSON.stringify(objectToSign), "base64", "utf8");
return signature;
};
// Test body
const BODY = {
testString: "hello",
testNumber: 12345,
testObject: {testArray: ["test1", "test2"]},
};
// Test query params
const QUERY = {
param1: "hello?this/is=a-test",
param2: "?yay!this/is/so#cool"
};
// Test id
const ID = "abc123";
// Timestamp and nonce for the request
// Note: always generate different nonce and timestamp for each request !
const TIMESTAMP = Math.round(new Date().valueOf() / 1000).toString();
const NONCE = Math.random()
.toString(36)
.substr(2, 8);
// Request signature
const signature = signRequest({
body: BODY,
query: QUERY,
timestamp: TIMESTAMP,
nonce: NONCE,
privateKey
});
// Request options
const options = {
host: "api.resolve.ch",
port: 443,
path: `/api/test/${ID}?${queryString.stringify(QUERY, { encode: true })}`,
method: "POST",
headers: {
"Content-Type": "application/json",
"X-RESOLVE-Authorization": `RESOLVE ${publicKey.replace(
/\\r?\\n|\\r/g,
""
)}:${signature}`, //Don't forget the signature
"X-RESOLVE-Nonce": NONCE,
"X-RESOLVE-Timestamp": TIMESTAMP
}
};
const req = https.request(options, result => {
result.setEncoding("utf8");
result.on("data", chunk => {
console.log(chunk);
});
});
req.on("error", error => {
console.error(error);
});
// Write the body
req.write(JSON.stringify(BODY));
req.end();