Hosting a WebHook endpoint

This document describes how to create a WebHook SmartApp.

Steps

  1. Create a web services application that can receive incoming HTTP POST requests to a publicly accessible endpoint via HTTPS. You can write and host your application using the language and tools of your choice.
  2. When creating your SmartApp, specify the endpoint URL of your app as the target URL, and select WEBHOOK as the app type. Your SmartApp must be reachable by SmartThings at this time, as it will be called with the PING lifecycle to verify its existence and health.
  3. Store the public key returned after creating your SmartApp. This will be used to verify incoming requests are sent from SmartThings.
  4. Ensure that all subsequent incoming requests are verified as coming from SmartThings, as documented below.

HTTP signature verification

All requests sent by SmartThings are signed in accordance with the IETF HTTP Signatures specification Draft 3 specification. A full discussion of HTTP signature verification is beyond the scope of this document; consult the specification referenced above, or see Joyent's page on http signing for more information.

The signature data is found on the authorization request header:

{
  "authorization": "Signature keyId=\"\/SmartThings\/80:34:9f:9f:51:84:7d:6d:40:21:63:44:9c:b1:78:44\",signature=\"AhTJ9uHjYbjMTWbToZ0ueRWu6gM52ueBRUSEm2H4xEyr4+cQ7zVN3IcZYsva3Kx0HcXU+2qiBlTmu4KgGW4PcANNV7bI8DUz\/cP6DNNyuGIveYQDe2XiG\/gnphyxfJHbPoGGmWAZaJfHaiutAW7GnzOmjGOfvsNX0xT\/PMOsUbyuJxMNw5btLrIYeenXQN4trD9GfudTljxaFRuFp\/an3A23qC0hxmweGaek3Tzn65\/iceWnok1gLDSo9IZCvGbjPc7UUZFzEdHNDsIOSHXMSwxLQntMl0UvfMytejT4p2X\/yJXlqHlBd\/GNwFGp4P8kj3iylMCXDEhbImx7dJ2Fnw==\",headers=\"(request-target) digest date\",algorithm=\"rsa-sha256\""
}

The public key you receive when creating your SmartApp is used to verify the request.

Various open-source libraries for different languages exist to provide HTTP signature verification, including:

Example


  const httpSignature = require('http-signature');
  const publicKey = fs.readFileSync('./config/smartthings_rsa.pub', 'utf8');

app.post('/smartthings', function (req, response) { // We don't yet have the public key during PING (when the app is created), // so no need to verify the signature. All other requests are verified. if (req.body && req.body.lifecycle === "PING" || signatureIsVerified(req)) { handleRequest(req, response); } else { response.status(401).send("Forbidden"); } });

function signatureIsVerified(req) { try { let parsed = httpSignature.parseRequest(req); if (!httpSignature.verifySignature(parsed, publicKey)) { console.log('forbidden - failed verifySignature'); return false; } } catch (error) { console.error(error); return false; } return true; }

function handleRequest(req, response) { // handle all lifecycles from SmartThings }

See also