Visual FoxPro Requires Chilkat v11.5.0+
Visual FoxPro
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 Visual FoxPro Downloads
LOCAL lnSuccess
LOCAL loRawBody
LOCAL lcTimestamp
LOCAL lcPrimarySignature
LOCAL lcSecondarySignature
LOCAL lcSignatureVersion
LOCAL lcSignatureAlgorithm
LOCAL lcPrimaryKey
LOCAL lcSecondaryKey
LOCAL loDelivered
LOCAL loNow
LOCAL lnAge
LOCAL loSignedBytes
LOCAL loMac
LOCAL lcExpectedPrimary
LOCAL lcExpectedSecondary
LOCAL loRandom
LOCAL lcComparisonKey
LOCAL lcPExpected
LOCAL lcPReceived
LOCAL lcSExpected
LOCAL lcSReceived
LOCAL lnValidPrimary
LOCAL lnValidSecondary
LOCAL loWebhookEvent
lnSuccess = 0
* Requires Chilkat 11.5.0 or later and a previously unlocked Chilkat bundle.
* See Global Unlock Sample.
* Guide: Box API Guide.
lnSuccess = 0
* Save the exact HTTP body bytes to this file, without JSON reserialization.
loRawBody = CreateObject('Chilkat.BinData')
lnSuccess = loRawBody.LoadFile("qa_data/box_webhook_body.bin")
IF (lnSuccess <> 1) THEN
? loRawBody.LastErrorText
RELEASE loRawBody
CANCEL
ENDIF
* Read these fields case-insensitively from the incoming request headers.
* For this offline example, enter the captured header values.
lcTimestamp = "BOX_DELIVERY_TIMESTAMP"
lcPrimarySignature = "BOX_SIGNATURE_PRIMARY"
lcSecondarySignature = "BOX_SIGNATURE_SECONDARY"
lcSignatureVersion = "1"
lcSignatureAlgorithm = "HmacSHA256"
* Retrieve configured keys from protected application configuration.
lcPrimaryKey = "BOX_PRIMARY_SIGNATURE_KEY"
lcSecondaryKey = "BOX_SECONDARY_SIGNATURE_KEY"
IF ((lcSignatureVersion <> "1") OR (lcSignatureAlgorithm <> "HmacSHA256")) THEN
? "Unsupported signature version or algorithm."
RELEASE loRawBody
CANCEL
ENDIF
loDelivered = CreateObject('Chilkat.CkDateTime')
lnSuccess = loDelivered.SetFromTimestamp(lcTimestamp)
IF (lnSuccess <> 1) THEN
? loDelivered.LastErrorText
RELEASE loRawBody
RELEASE loDelivered
CANCEL
ENDIF
loNow = CreateObject('Chilkat.CkDateTime')
lnSuccess = loNow.SetFromCurrentSystemTime()
IF (lnSuccess <> 1) THEN
? loNow.LastErrorText
RELEASE loRawBody
RELEASE loDelivered
RELEASE loNow
CANCEL
ENDIF
lnAge = VAL(loNow.GetAsUnixTime(0)) - VAL(loDelivered.GetAsUnixTime(0))
* Box recommends rejecting deliveries older than ten minutes.
* Allow at most 60 seconds of future clock skew; keep the server clock synchronized.
IF ((lnAge > 600) OR (lnAge < -60)) THEN
? "Delivery timestamp is outside the accepted window."
RELEASE loRawBody
RELEASE loDelivered
RELEASE loNow
CANCEL
ENDIF
loSignedBytes = CreateObject('Chilkat.BinData')
lnSuccess = loSignedBytes.AppendBd(loRawBody)
IF (lnSuccess <> 1) THEN
? loSignedBytes.LastErrorText
RELEASE loRawBody
RELEASE loDelivered
RELEASE loNow
RELEASE loSignedBytes
CANCEL
ENDIF
lnSuccess = loSignedBytes.AppendString(lcTimestamp,"utf-8")
IF (lnSuccess <> 1) THEN
? loSignedBytes.LastErrorText
RELEASE loRawBody
RELEASE loDelivered
RELEASE loNow
RELEASE loSignedBytes
CANCEL
ENDIF
loMac = CreateObject('Chilkat.Crypt2')
loMac.MacAlgorithm = "hmac"
loMac.HashAlgorithm = "sha256"
loMac.EncodingMode = "base64"
lnSuccess = loMac.SetMacKeyString(lcPrimaryKey)
IF (lnSuccess <> 1) THEN
? loMac.LastErrorText
RELEASE loRawBody
RELEASE loDelivered
RELEASE loNow
RELEASE loSignedBytes
RELEASE loMac
CANCEL
ENDIF
lcExpectedPrimary = loMac.MacBdENC(loSignedBytes)
IF (loMac.LastMethodSuccess <> 1) THEN
? loMac.LastErrorText
RELEASE loRawBody
RELEASE loDelivered
RELEASE loNow
RELEASE loSignedBytes
RELEASE loMac
CANCEL
ENDIF
lnSuccess = loMac.SetMacKeyString(lcSecondaryKey)
IF (lnSuccess <> 1) THEN
? loMac.LastErrorText
RELEASE loRawBody
RELEASE loDelivered
RELEASE loNow
RELEASE loSignedBytes
RELEASE loMac
CANCEL
ENDIF
lcExpectedSecondary = loMac.MacBdENC(loSignedBytes)
IF (loMac.LastMethodSuccess <> 1) THEN
? loMac.LastErrorText
RELEASE loRawBody
RELEASE loDelivered
RELEASE loNow
RELEASE loSignedBytes
RELEASE loMac
CANCEL
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.
loRandom = CreateObject('Chilkat.Prng')
lcComparisonKey = loRandom.GenRandom(32,"base64")
IF (loRandom.LastMethodSuccess <> 1) THEN
? loRandom.LastErrorText
RELEASE loRawBody
RELEASE loDelivered
RELEASE loNow
RELEASE loSignedBytes
RELEASE loMac
RELEASE loRandom
CANCEL
ENDIF
lnSuccess = loMac.SetMacKeyEncoded(lcComparisonKey,"base64")
IF (lnSuccess <> 1) THEN
? loMac.LastErrorText
RELEASE loRawBody
RELEASE loDelivered
RELEASE loNow
RELEASE loSignedBytes
RELEASE loMac
RELEASE loRandom
CANCEL
ENDIF
lcPExpected = loMac.MacStringENC(lcExpectedPrimary)
IF (loMac.LastMethodSuccess <> 1) THEN
? loMac.LastErrorText
RELEASE loRawBody
RELEASE loDelivered
RELEASE loNow
RELEASE loSignedBytes
RELEASE loMac
RELEASE loRandom
CANCEL
ENDIF
lcPReceived = loMac.MacStringENC(lcPrimarySignature)
IF (loMac.LastMethodSuccess <> 1) THEN
? loMac.LastErrorText
RELEASE loRawBody
RELEASE loDelivered
RELEASE loNow
RELEASE loSignedBytes
RELEASE loMac
RELEASE loRandom
CANCEL
ENDIF
lcSExpected = loMac.MacStringENC(lcExpectedSecondary)
IF (loMac.LastMethodSuccess <> 1) THEN
? loMac.LastErrorText
RELEASE loRawBody
RELEASE loDelivered
RELEASE loNow
RELEASE loSignedBytes
RELEASE loMac
RELEASE loRandom
CANCEL
ENDIF
lcSReceived = loMac.MacStringENC(lcSecondarySignature)
IF (loMac.LastMethodSuccess <> 1) THEN
? loMac.LastErrorText
RELEASE loRawBody
RELEASE loDelivered
RELEASE loNow
RELEASE loSignedBytes
RELEASE loMac
RELEASE loRandom
CANCEL
ENDIF
lnValidPrimary = (lcPrimaryKey <> "") AND (lcPrimarySignature <> "") AND (lcPExpected = lcPReceived)
lnValidSecondary = (lcSecondaryKey <> "") AND (lcSecondarySignature <> "") AND (lcSExpected = lcSReceived)
IF ((lnValidPrimary = 0) AND (lnValidSecondary = 0)) THEN
? "Signature verification failed."
RELEASE loRawBody
RELEASE loDelivered
RELEASE loNow
RELEASE loSignedBytes
RELEASE loMac
RELEASE loRandom
CANCEL
ENDIF
* Parse JSON only after signature verification.
loWebhookEvent = CreateObject('Chilkat.JsonObject')
lnSuccess = loWebhookEvent.Load(loRawBody.GetString("utf-8"))
IF (lnSuccess <> 1) THEN
? loWebhookEvent.LastErrorText
RELEASE loRawBody
RELEASE loDelivered
RELEASE loNow
RELEASE loSignedBytes
RELEASE loMac
RELEASE loRandom
RELEASE loWebhookEvent
CANCEL
ENDIF
? "Verified event ID: " + loWebhookEvent.StringOf("id")
? "Trigger: " + loWebhookEvent.StringOf("trigger")
* Deduplicate using event.id, not BOX-DELIVERY-ID, which changes on retries.
* Verify the target belongs to your configured webhook before dispatching work.
RELEASE loRawBody
RELEASE loDelivered
RELEASE loNow
RELEASE loSignedBytes
RELEASE loMac
RELEASE loRandom
RELEASE loWebhookEvent