When you configure a subscription to receive events of your parallels, you can additionally create one or more signature keys for that subscription.
Signature keys can be used to verify:
Authenticity: The events you receive are sent by Parallel.
Integrity: The contents of the event are the same as they were at the time of sending.
This is very important for making sure that nobody else can send events to your webhooks other than Parallel, and that those events were not modified at any given moment.
Parallel uses the Ed25519 algorithm for signing the requests. Ed25519 is a modern signature algorithm with implementations in most programming languages.
How to configure signature keys:
Go to your developers dashboard. (Only Admins have access to this section)
Click on the Create subscription button. (Or select any of your current subscriptions and click on Edit)
After you have completed the initial configuration of the subscription, click on Continue.
The next configuration step will appear, where you can optionally add one or more signature keys for that subscription.
Click on Add to add up to 5 signature keys.
Each created signature key will appear below, where you can easily copy or delete it.
These are public keys used to verify the signature. Parallel stores securely the private keys needed to create the signatures.
After the configuration is completed, you can click on the "keys" text in the table to see and manage your keys.
How to use your signature keys:
Once you have set the signature keys on your subscription, the next step is to use them to verify your events.
For each signature key set, we will include additional header values on the POST requests that we send to the subscription events URL. For example, if you created two signature keys, we will send two special headers: X-Parallel-Signature-V2-1 and X-Parallel-Signature-V2-2, each one containing a base64 encoded text, or event signature.
You can use these event signatures to validate the events, alongside one of the signature keys you created.
You should use only one of the signature keys at a time to validate the event signatures in your application. Parallel allows multiple keys to make it easier to rotate keys without downtime.
Verifying the event signatures:
STEP 1: Receive a message. After you configured a subscription and its signature keys, your application will start receiving events from your parallels. Each event you receive will contain special headers with the event signatures, one for each defined signature key. It will also contain a X-Parallel-Signature-Timestamp header to be used as part of the payload to verify.
X-Parallel-Signature-V2-1: f1xUDPzfj37682KsU+1XTj1zfelJVlia9R...
X-Parallel-Signature-Timestamp: 1726842968464
STEP 2: Verify the signatures. Use any of your signature keys to try to verify the event signatures. Only one signature must be valid to ensure the authenticity and integrity of the event. Below you find some code snippets on how to validate the autenticity.
In order to build the payload for verifying, you need to create a Buffer concatenating the request URL + request timestamp + raw request body.
Note: Make sure you use the raw body of the request. If the request is parsed and then stringified, the raw body may differ due to whitespace differences.
Code snippets
Node.js
const crypto = require("crypto");
/**
* Validates the given payload using the specified public key and signature.
* @param {Buffer} payload The payload of the request. Its composed concatenating the request URL, timestamp and raw body. You can find the timestamp in the X-Parallel-Signature-Timestamp header.
* @param {string} publicKey The public key to use.
* @param {string} signature The signature to validate.
* @returns {boolean} true if the provided signature is valid; otherwise, <c>false</c>.
*/
function isValidPayload(payload, publicKey, signature) {
return crypto.verify(
null,
payload,
{
key: Buffer.from(publicKey, "base64"),
format: "der",
type: "spki"
},
Buffer.from(signature, "base64")
);
}
C#
Using the NSec.Cryptography library.
using System.Text;
using NSec.Cryptography;
/// <summary>
/// Validates the given payload using the specified public key and signature.
/// </summary>
/// <param name="payload">The payload of the request. Its composed concatenating the request URL, timestamp and raw body. You can find the timestamp in the X-Parallel-Signature-Timestamp header.</param>
/// <param name="publicKey">The public key to use.</param>
/// <param name="signature">The signature to validate.</param>
/// <returns><c>true</c> if the payload is valid; otherwise, <c>false</c>.</returns>
static bool IsValidPayload(Stream payload, string publicKey, string signature)
{
ReadOnlySpan<byte> _payload;
using (var ms = new MemoryStream())
{
payload.CopyTo(ms);
_payload = new ReadOnlySpan<byte>(ms.ToArray());
}
var algorithm = new Ed25519();
var _publicKey = PublicKey.Import(algorithm, new ReadOnlySpan<byte>(Convert.FromBase64String(publicKey)), KeyBlobFormat.PkixPublicKey);
var _signature = new ReadOnlySpan<byte>(Convert.FromBase64String(signature));
return algorithm.Verify(_publicKey, _payload, _signature);
}