This page explains how Verification signs callbacks to your backend, allowing you to authenticate the callback source.
The Sinch Platform can initiate callback requests to a URL you define (Callback URL) on request and result events. All callback requests are signed using your Application key and secret pair found on your dashboard. The signature is included in the Authorization header of the request.
Authorization = "Application" + " " + ApplicationKey + ":" + Signature
Signature = Base64 ( HMAC-SHA256 ( Base64-Decode( ApplicationSecret ), UTF8 ( StringToSign ) ) );
StringToSign = HTTP-Verb + "\n" +
Request-Body-Content-MD5 + "\n" +
Request-Content-Type + "\n" +
Request-CanonicalizedHeaders + "\n" +
Request-CanonicalizedResource;
Request-Body-Content-MD5 = Base64 ( MD5 ( [REQUEST-BODY] ) )| Pseudocode Component | Description |
|---|---|
Request-Content-Type | The value of the Content-Type header of the callback request: application/json; charset=utf-8. |
Request-CanonicalizedHeaders | The only required header is x-timestamp. |
Request-CanonicalizedResource | The path of your Callback URL, without host, port, or query string. For example, /sinch/callback/result. |
ApplicationKey | The key for your Voice application found on your dashboard. |
ApplicationSecret | The secret for your Voice application found on your dashboard. Important!: The Application Secret value must be base64-decoded from before it's used for signing. |
Sinch sends a custom request header x-timestamp (time) with each request that can be validated by your server. This custom header is used to determine that the request is not too old. The timestamp is also part of the signature. The timestamp is formatted to ISO 8061 specifications.
The timestamp must be in the Coordinated Universal Time (UTC) timezone.
x-timestamp: 2014-06-02T15:39:31.2729234ZIn this example, assume that the Callback URL is configured as "https://callbacks.yourdomain.com/sinch/callback/result"
ApplicationKey = 669E367E-6BBA-48AB-AF15-266871C28135
ApplicationSecret = BeIukql3pTKJ8RGL5zo0DA==Body (the MD5 below is calculated over exactly these bytes: 2-space indentation, \n line endings, no trailing newline)
{
"id": "1234567890",
"event": "VerificationResultEvent",
"method": "sms",
"identity": {
"type": "number",
"endpoint": "+11235551234"
},
"status": "PENDING",
"reason": "Fraud",
"reference": "12345",
"source": "intercept",
"custom": "string"
}Request-Body-Content-MD5 = Base64 ( MD5 ( [BODY] ) )
SI5URNZQlDbGI6BP5BgmYQ==
StringToSign
POST
SI5URNZQlDbGI6BP5BgmYQ==
application/json; charset=utf-8
x-timestamp:2014-09-24T10:59:41Z
/sinch/callback/result
Signature = Base64 ( HMAC-SHA256 ( Base64-Decode( ApplicationSecret ), UTF8 ( StringToSign ) ) )
TwNofUj4kCL0mhWaMGhqF1jVR5NGK3Fly9g5gkxPg+c=
HTTP Authorization Header
Authorization: Application 669E367E-6BBA-48AB-AF15-266871C28135:TwNofUj4kCL0mhWaMGhqF1jVR5NGK3Fly9g5gkxPg+c=Calculate the MD5 over the raw request body bytes exactly as received. Parsing and re-serializing the JSON changes the bytes and produces a different MD5.
The Application Secret value must be base64-decoded from before it's used for signing.
Your development platform that receives the callbacks can verify that the request originated from Sinch by calculating the signature as described above and compare the result with the value contained in the Application HTTP header.
You can clone this repository to see how this is implemented in Java, ASP.NET, Python, PHP, and Node.js.



