AutoIt Requires Chilkat v11.5.0+
AutoIt
Box: Verify a Captured V2 Webhook Signature
See more Box Examples
Verify raw payload bytes and captured headers using the configured primary and secondary signing keys. The example rejects stale/future timestamps and compares randomized HMACs of the signatures to avoid exposing a signature-prefix timing comparison. It does not host an HTTP listener. The receiver must persist/deduplicate the verified event and acknowledge promptly.
See the Box API guide for setup and the complete workflow.
Chilkat AutoIt Downloads
Local $bSuccess = False
; Requires Chilkat 11.5.0 or later and a previously unlocked Chilkat bundle.
; See Global Unlock Sample.
; Guide: Box API Guide.
$bSuccess = False
; Save the exact HTTP body bytes to this file, without JSON reserialization.
$oRawBody = ObjCreate("Chilkat.BinData")
$bSuccess = $oRawBody.LoadFile("qa_data/box_webhook_body.bin")
If ($bSuccess <> True) Then
ConsoleWrite($oRawBody.LastErrorText & @CRLF)
Exit
EndIf
; Read these fields case-insensitively from the incoming request headers.
; For this offline example, enter the captured header values.
Local $sTimestamp = "BOX_DELIVERY_TIMESTAMP"
Local $sPrimarySignature = "BOX_SIGNATURE_PRIMARY"
Local $secondarySignature = "BOX_SIGNATURE_SECONDARY"
Local $signatureVersion = "1"
Local $signatureAlgorithm = "HmacSHA256"
; Retrieve configured keys from protected application configuration.
Local $sPrimaryKey = "BOX_PRIMARY_SIGNATURE_KEY"
Local $secondaryKey = "BOX_SECONDARY_SIGNATURE_KEY"
If (($signatureVersion <> "1") Or ($signatureAlgorithm <> "HmacSHA256")) Then
ConsoleWrite("Unsupported signature version or algorithm." & @CRLF)
Exit
EndIf
$oDelivered = ObjCreate("Chilkat.CkDateTime")
$bSuccess = $oDelivered.SetFromTimestamp($sTimestamp)
If ($bSuccess <> True) Then
ConsoleWrite($oDelivered.LastErrorText & @CRLF)
Exit
EndIf
$oNow = ObjCreate("Chilkat.CkDateTime")
$bSuccess = $oNow.SetFromCurrentSystemTime()
If ($bSuccess <> True) Then
ConsoleWrite($oNow.LastErrorText & @CRLF)
Exit
EndIf
Local $iAge = Int($oNow.GetAsUnixTime(False)) - Int($oDelivered.GetAsUnixTime(False))
; Box recommends rejecting deliveries older than ten minutes.
; Allow at most 60 seconds of future clock skew; keep the server clock synchronized.
If (($iAge > 600) Or ($iAge < -60)) Then
ConsoleWrite("Delivery timestamp is outside the accepted window." & @CRLF)
Exit
EndIf
$oSignedBytes = ObjCreate("Chilkat.BinData")
$bSuccess = $oSignedBytes.AppendBd($oRawBody)
If ($bSuccess <> True) Then
ConsoleWrite($oSignedBytes.LastErrorText & @CRLF)
Exit
EndIf
$bSuccess = $oSignedBytes.AppendString($sTimestamp,"utf-8")
If ($bSuccess <> True) Then
ConsoleWrite($oSignedBytes.LastErrorText & @CRLF)
Exit
EndIf
$oMac = ObjCreate("Chilkat.Crypt2")
$oMac.MacAlgorithm = "hmac"
$oMac.HashAlgorithm = "sha256"
$oMac.EncodingMode = "base64"
$bSuccess = $oMac.SetMacKeyString($sPrimaryKey)
If ($bSuccess <> True) Then
ConsoleWrite($oMac.LastErrorText & @CRLF)
Exit
EndIf
Local $sExpectedPrimary = $oMac.MacBdENC($oSignedBytes)
If ($oMac.LastMethodSuccess <> True) Then
ConsoleWrite($oMac.LastErrorText & @CRLF)
Exit
EndIf
$bSuccess = $oMac.SetMacKeyString($secondaryKey)
If ($bSuccess <> True) Then
ConsoleWrite($oMac.LastErrorText & @CRLF)
Exit
EndIf
Local $sExpectedSecondary = $oMac.MacBdENC($oSignedBytes)
If ($oMac.LastMethodSuccess <> True) Then
ConsoleWrite($oMac.LastErrorText & @CRLF)
Exit
EndIf
; Blind both sides with a fresh secret random key before equality comparison.
; Never compare the original HMAC strings using a prefix-short-circuit comparison.
; A host-language receiver can instead use its standard constant-time byte comparison.
$oRandom = ObjCreate("Chilkat.Prng")
Local $sComparisonKey = $oRandom.GenRandom(32,"base64")
If ($oRandom.LastMethodSuccess <> True) Then
ConsoleWrite($oRandom.LastErrorText & @CRLF)
Exit
EndIf
$bSuccess = $oMac.SetMacKeyEncoded($sComparisonKey,"base64")
If ($bSuccess <> True) Then
ConsoleWrite($oMac.LastErrorText & @CRLF)
Exit
EndIf
Local $sPExpected = $oMac.MacStringENC($sExpectedPrimary)
If ($oMac.LastMethodSuccess <> True) Then
ConsoleWrite($oMac.LastErrorText & @CRLF)
Exit
EndIf
Local $sPReceived = $oMac.MacStringENC($sPrimarySignature)
If ($oMac.LastMethodSuccess <> True) Then
ConsoleWrite($oMac.LastErrorText & @CRLF)
Exit
EndIf
Local $sExpected = $oMac.MacStringENC($sExpectedSecondary)
If ($oMac.LastMethodSuccess <> True) Then
ConsoleWrite($oMac.LastErrorText & @CRLF)
Exit
EndIf
Local $sReceived = $oMac.MacStringENC($secondarySignature)
If ($oMac.LastMethodSuccess <> True) Then
ConsoleWrite($oMac.LastErrorText & @CRLF)
Exit
EndIf
Local $bValidPrimary = ($sPrimaryKey <> "") And ($sPrimarySignature <> "") And ($sPExpected = $sPReceived)
Local $bValidSecondary = ($secondaryKey <> "") And ($secondarySignature <> "") And ($sExpected = $sReceived)
If (($bValidPrimary = False) And ($bValidSecondary = False)) Then
ConsoleWrite("Signature verification failed." & @CRLF)
Exit
EndIf
; Parse JSON only after signature verification.
$oWebhookEvent = ObjCreate("Chilkat.JsonObject")
$bSuccess = $oWebhookEvent.Load($oRawBody.GetString("utf-8"))
If ($bSuccess <> True) Then
ConsoleWrite($oWebhookEvent.LastErrorText & @CRLF)
Exit
EndIf
ConsoleWrite("Verified event ID: " & $oWebhookEvent.StringOf("id") & @CRLF)
ConsoleWrite("Trigger: " & $oWebhookEvent.StringOf("trigger") & @CRLF)
; Deduplicate using event.id, not BOX-DELIVERY-ID, which changes on retries.
; Verify the target belongs to your configured webhook before dispatching work.