Skip to main content

Request authentication

A notification request from webhooks can be verified by using the host, x-ms-date, x-ms-content-sha256, and authorization headers with the unique secret received when the webhook was registered. The authorization is a sha256 HMAC hash of the request date, content, and URI that is created using the webhook secret.

import crypto from "crypto";

// The secret is found in the response body when you register a webhook.
// Note: The secret is unique per hook registration, which may cover multiple event types.
const secret = 'A0+AeKBRG2KRGvnNwJpQlb6IJFk48CKXCIcrLoHncVJKDILsQSxS6NWCccwWm6r6FhGKhiHTBsG2wo/xU6FY/A=='

const requestUrl = "https://webhook.site/e2cee29b-012e-4f1d-8ef4-e95fd74a7a63"
// Part of the HTTP request header from Vipps MobilePay, found in the field 'x-ms-date'
const dateTime = "Thu, 30 Mar 2023 08:38:32 GMT"

// The signature/authorization sent by Vipps MobilePay for you to verify against.
// Part of the HTTP request header from Vipps MobilePay, found in the field 'authorization'
const actualSignature = "HMAC-SHA256 SignedHeaders=x-ms-date;host;x-ms-content-sha256&Signature=agAiSyogQbDHpeucoNwYz+yAr5nJ+v+zasdkSbqzv+U="

const httpBody = {
"some-unique-content":"ee6e441b-cc4a-46f8-895d-a5af79bcc233/hello-world"
}

const hashedPayload = crypto
.createHash("sha256")
.update(JSON.stringify(httpBody))
.digest("base64") // evaluates to 'lNlsp1XA03N34HrQsVzPgJKtC+r7l/RBF4V3JQUWMj4='

const url = new URL(requestUrl)
const pathAndQuery = url.pathname + url.search; // '/e2cee29b-012e-4f1d-8ef4-e95fd74a7a63'
const host = url.host // 'webhook.site'

const expectedSignedString = `POST\n${pathAndQuery}\n${dateTime};${host};${hashedPayload}`
/* evaluates to:
POST
/e2cee29b-012e-4f1d-8ef4-e95fd74a7a63
Thu, 30 Mar 2023 08:38:32 GMT;webhook.site;lNlsp1XA03N34HrQsVzPgJKtC+r7l/RBF4V3JQUWMj4=
*/

// Run the HMAC SHA256 algorithm on the expectedSignedString with the secret for the hook
const expectedSignature = crypto.createHmac("sha256", secret)
.update(expectedSignedString)
.digest("base64")
// evaluates to: 'agAiSyogQbDHpeucoNwYz+yAr5nJ+v+zasdkSbqzv+U='

const expectedAuth = `HMAC-SHA256 SignedHeaders=x-ms-date;host;x-ms-content-sha256&Signature=${expectedSignature}`

if(expectedAuth !== actualSignature) {
// Log the error.
// Fail, stop processing
throw new Error('Authorization fields do not match expected value!');
}
console.log('Success! Business logic awaits!')

Help us improve our documentation

Did you find what you were looking for?