These docs are for v3.0. Click to read the latest docs for v3.1.

Mutual TLS

Mutual TLS Authentication

All API calls done to our gateway require mutual TLS authentication using your QWAC certificate.

During the TLS handshake, you will be presented with Shine's own QWAC certificate.
Our QWAC certificate has been delivered by CertEurope and the root certificate can be found here https://www.certeurope.fr/chaine-de-confiance/.

Here an exemple on how to make a mTLS request

curl --cert client-cert.pem --key client-key.pem https://www.example.com/
const https = require('https');
const fs = require('fs');

// HTTPS request options
const options = {
  hostname: 'www.example.com',
  port: 443,
  path: '/',
  method: 'GET',
  // Client certificates for mutual TLS authentication
  key: fs.readFileSync('YOUR_QWAC_KEY.pem'),
  cert: fs.readFileSync('YOUR_QWAC_CERT.pem'),
};

// Callback function to handle the HTTPS response
function handleResponse(response) {
  // Your implementation
}

// Make the HTTPS request
const req = https.request(options, handleResponse);
req.end();

HTTP Signature

The request must be signed with your QSEAL certificate according to the draft specification https://datatracker.ietf.org/doc/draft-cavage-http-signatures/.

The algorithm used for the signature must be RSA-SHA256

At least the following headers and their content must be signed using your QSEAL

(request-target)
date
psu-ip-address
psu-ip-port
psu-http-method
psu-date psu-user-agent
psu-referer psu-accept
psu-accept-charset
psu-accept-encoding
psu-accept-language

The Signature header must include the signature containing the following fields:

  • keyId (your organization identifier)
  • algorithm (rsa-sha256)
  • headers (list of signed headers)
  • signature
Signature=keyId="PSDFR-ACPR-XXXXX",algorithm="rsa-sha256",headers="(request-target) date psu-ip-address psu-ip-port psu-http-method psu-date psu-user-agent psu-referer psu-accept psu-accept-charset psu-accept-encoding psu-accept-language",signature="OkLTdS4RUygYG7jIuekxJE1LLRnepTNEOr7UnqbRO2wJhYoSnmvRsnR9/HBOGaWPHADwdErSNi8W/muAtGF+xNpsfylrZl0Q2lZT2Wqgq6gRbcVMf1pRhU8VA4IYLuAwVrujIbdimrhIFBq2KKyPfOHce8v52/Zj/RrbEq2oW0NMPBh5PqNIlMY/zml1ZbBaprK6zxObhNpU6uhp3w2ZdXK5lmkD64bGVFlYTqn3c1FDTw62wgjEUtUGw62qwftOP9nE/bVHhERGqQN33HozdpSl6j+QZgVUgClZZrhKFOUbkUfhO8EosWEcTccnweR49JhMcYebBwJY3uuhVUmXCg=="

If your request contains a body, you will need to add a signed digest header.
Here is an example to generate a body digest:

const crypto = require('crypto');

/**
Generates a cryptographic digest using the SHA256 algorithm and a private key to sign it in base64 encoding.
@param {string} body
@param {string | Buffer} privateKek
@returns {string} - The signed hash in base64 encoding.
*/
const generateDigest = (body, privateKey) => {
  const sign = crypto.createSign('SHA256');
  sign.write(body);
  sign.end();
  return sign.sign(privateKey, 'base64');
};

When you receive a response from our gateway, you must verify the signature contained in the Authorization header and ensure all the required headers and their content are signed.

You will be able to get our QSEAL certificate at the URI present in the keyId field.

Here is an example how to verify the HTTP signature:

const crypto = require('crypto');

/**
Validates the signature of a cryptographic digest using the SHA256 algorithm and a public key.
@param {string} body
@param {string} signature - The signed hash in base64 encoding.
@param {string | Buffer} publicKey
@returns {boolean} - Whether or not the signature is valid.
*/
const validateSignature = (body, signature, shinePublicKey) => {
  const verify = crypto.createVerify('SHA256');
  verify.write(body);
  verify.end();
  return verify.verify(shinePublicKey, signature, 'base64');
};