Signing secret validation

Here is a sample script that can be used to validate the signing secret that is sent with payloads coming from your Seismic hosted app.

[HttpPost("config")]
public async Task<IActionResult> Configuration()
{
    using (var memoryStream = new System.IO.MemoryStream())
    {
        await this.HttpContext.Request.Body.CopyToAsync(memoryStream);
        var key = System.Text.Encoding.UTF8.GetBytes(signingSecret); // the app's signing secret

        using (var hmac = new System.Security.Cryptography.HMACSHA256(key))
        {
            var body = memoryStream.ToArray();
            byte[] bodyHash = hmac.ComputeHash(body);
            var computed = System.BitConverter.ToString(bodyHash).Replace("-", "");
            var incoming = this.HttpContext.Request.Headers["x-seismic-signature"];

            var bodyString = System.Text.Encoding.UTF8.GetString(body);
            var json = Newtonsoft.Json.Linq.JToken.Parse(bodyString);

            var requestTime = json.Value<DateTime>("timestamp");

            // Validate signatures match and request not more than 2 minutes old.
            if ((incoming != computed) || DateTime.UtcNow - requestTime > TimeSpan.FromMinutes(2))
                return Unauthorized();

            var appId = json.Value<string>("appId");
            var appName = json.Value<string>("appName");
            var tenantId = json.Value<string>("tenantId");
            var tenantName = json.Value<string>("tenant");
            var version = json.Value<string>("version");
            var userId = json.Value<string>("userId");
            var userEmail = json.Value<string>("userEmail");
            var language = json.Value<string>("language");

            return View(new { appId, appName, tenantId, tenantName, version });// or serve the config page in some other way.
        }
    }
}

Additional information regarding the sample code:

  • Read the request body as is, without any transformations or parsing, as bytes.
  • Computes its hmac signature using the app's signing secret.
  • Parse the body as a json and read the timestamp.
  • Execute validations.
  • The computed signature matches the incoming signature in the header.
  • The request is no more than 2 minutes old.
  • Return an error if validations fail.

All request payloads also carry a timestamp object. It is recommended that all apps verify requests are no more than 2 minutes old. Not building this check may lead to request replays. All timestamps are in yyyy-MM-ddTHH:mm:ssZ format and are based on UTC.