
Security News
OWASP 2025 Top 10 Adds Software Supply Chain Failures, Ranked Top Community Concern
OWASP’s 2025 Top 10 introduces Software Supply Chain Failures as a new category, reflecting rising concern over dependency and build system risks.
ciscospark-webhook-validator
Advanced tools
Use co-body and dataloader to validate incoming webhooks from Cisco Spark
Official documentation available at: https://developer.ciscospark.com/webhooks-explained.html
This module facilitates business-logic that operates on a Cisco Spark webhook payload, such as:
const businessLogic = ({ data, event, resource }) => {
const isMessagesCreated = resource === 'messages' && event === 'created'
if (!isMessagesCreated || data.personEmail.endsWith('@sparkbot.io')) return
console.log('some human (not a Bot) created new Spark message(s):', data)
}
The default Spark export provides a safe validate Function that can be customized for optimal efficiency.
In your project: npm install --save ciscospark-webhook-validator
In server.js, or elsewhere in your application's module(s):
// see sections below for basic usage or full customization:
const { validate } = require('ciscospark-webhook-validator')
const server = require('http').createServer(/* listener */)
// event listener fires business-logic only for valid webhook payloads
// (a payload is valid if and only if its HMAC matches X-Spark-Signature)
// possible responses are: 202 Accepted / 406 Not Acceptable (no body)
server.on('request', (req, res) => {
const onceAccepted = () => Object.assign(res, { statusCode: 202 }).end()
const onceNotAcceptable = () => Object.assign(res, { statusCode: 406 }).end()
validate(req).then(businessLogic).then(onceAccepted, onceNotAcceptable)
})
// with async / await (or co / yield) validation could be:
// request.body = await validate(req).catch(() => null)
// if (request.body) businessLogic(request.body)
ngrokif (process.env.CISCOSPARK_ACCESS_TOKEN) {
const port = process.env.PORT || 8080
server.listen({ port }, (listenError) => {
if (listenError) {
console.error(listenError)
process.exitCode = 1
} else {
console.log(`listening on PORT=${port}`)
}
})
}
// PROTIP: in another terminal, run these commands:
// npm install ngrok # https://www.npmjs.com/package/ngrok
// node_modules/.bin/ngrok http $PORT # targetUrl is HTTPS
// with your token from https://developer.ciscospark.com/
// create a new Spark webhook w/ $secret and $targetUrl
// open http://localhost:4040/ in your favorite browser
~100 SLOC is provided by a single ES6 module. (and test coverage is complete)
NodeJS's crypto.timingSafeEqual is used to compare the contents of Buffers.
N.B. Legacy applications may require('ciscospark-webhook-validator/es5').
Via co-body a req's body is digested as text and then JSON.parse'd.
Using HTTPS + Authorization, that webhook's secret is requested from Spark.
X-Spark-Signature is compared against the digest; validated JSON is returned.
Correctness follows from use of the webhook's fetched secret for HMAC validation.
Efficiently is achieved through use of a RequestCache such that:
validate that run on the same request are coalescedvalidate that load the same token do so exactly oncevalidate that load the same webhook do so exactly onceThe first relies on the RequestCache (WeakMap) implementation.
The second and third are a facility of the dataloader implementation.
A basic example is included above. See the next section for advanced usage.
It is easy to adjust the validation process for many special circumstances:
CISCOSPARK_ACCESS_TOKENSpark.getAccessToken may be replaced with a Promise-returning FunctionSpark.getWebhookDetails may be replaced similarly (see examples below)Spark.RequestCache and Spark.ResponseError type(s) may be replacedIf your application is a bot, the easiest way to provide its token is via environment variables:
process.env.CISCOSPARK_ACCESS_TOKEN = ... // all future requests to Spark will use this, by default
By default, one request is made to Spark for each unique webhook registered to your application.
For example, if your application loads tokens from a secret store:
const Spark = require('ciscospark-webhook-validator')
Spark.getAccessToken = creatorID => vault.getAccessToken(creatorID)
For example, if your application makes use of a single, static webhook:
const Spark = require('ciscospark-webhook-validator')
Spark.getWebhookDetails = () => Promise.resolve({ secret: '...' })
For example, if you want to test against a self-hosted, mock, or other implementation of the Spark APIs:
const Spark = require('ciscospark-webhook-validator')
Spark.getAPIEndpoint = () => 'my.spark.endpoint.com'
FAQs
Use co-body and dataloader to validate incoming webhooks from Cisco Spark
We found that ciscospark-webhook-validator demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
OWASP’s 2025 Top 10 introduces Software Supply Chain Failures as a new category, reflecting rising concern over dependency and build system risks.

Research
/Security News
Socket researchers discovered nine malicious NuGet packages that use time-delayed payloads to crash applications and corrupt industrial control systems.

Security News
Socket CTO Ahmad Nassri discusses why supply chain attacks now target developer machines and what AI means for the future of enterprise security.