Webhook HMAC validation

Outgoing webhooks from Challengermode to your servers will always include HMAC headers that can be used to validate thatChallengermode initiated the request.In your Application Dashboard, you will find a pre-shared key (PSK) which can be used to add HMAC validation to your webhooks:
// Compute content hash.
computedChecksum = ComputeSHA256Hash(request.Body).ToBase64();

// Prepare string to sign.
timestamp = request.Headers["Cm-Date"];
// Example:
// POST
// /api/cm/get_game_account
// 2021-11-09T13:52:27.4637477+00:00;example.com;t2jaQHi3fQt0FQ2HPtUeY/TGVNgQmspupcaUUYytrYI=
stringToSign = "{request.Method}\n{request.PathAndQuery}\n{timestamp};{request.Authority};{computedChecksum}";

// Compute and validate signature.
computedSignature = Base64Encode(HMACSHA256.Compute(stringToSign, PreSharedKey));
claimedSignature = request.Headers.Authorization.Split("Signature=")[1];
if (claimedSignature != computedSignature)
{
    return AuthenticateResult.Fail("Invalid HMAC signature");
}

Authorize();
Additional checks are optional but recommended:
// Validate expiry.
if (DateTime.UtcNow - DateTime.ParseIso8601(timestamp) > Lifespan)
{
    return AuthenticateResult.Fail("Timestamp is too old");
}

// Validate checksum.
claimedChecksum = request.Headers["Content-SHA256"];
if (claimedChecksum != computedChecksum)
{
    return AuthenticateResult.Fail("Incorrect checksum");
}

// Validate timestamp uniqueness.
if (Cache.Contains(timestamp))
{
    return AuthenticateResult.Fail("Timestamp not unique");
}
Cache.Add(timestamp, DateTime.UtcNow + Lifespan);