Hosting a WebHook endpoint

This document describes how to create a WebHook SmartApp.

Steps

The following are the general steps needed to create a Webhook SmartApp. Additional details will be provided in the following sections.

  1. Create a web service application. See the SmartThings Node SDK or SmartThings Java SDK for an easy way to get started.
  2. Register your Webhook SmartApp with SmartThings. You will need a publicly accessible HTTPS url.
  3. Verify your domain ownership using the confirmation lifecycle.
  4. Ensure that all incoming HTTP traffic is properly authorized to have originated from SmartThings.

Verify your domain ownership

Verification is the process of proving that you own the domain that you desire to register as the root for a Webhook SmartApp. We need to confirm ownership to ensure SmartThings is not sending unsolicited HTTP traffic to a domain.

Confirmation Lifecycle

Verification is provided through successful completion of the confirmation lifecycle. During the confirmation lifecycle your Webhook SmartApp will receive an HTTP request like the following to the target url you previously specified:


    {
      "lifecycle": "CONFIRMATION",
      "confirmationData": {
        "appId": "{YOUR_APP_ID}",
        "confirmationUrl": "{CONFIRMATION_URL}"
      }
    }      
  

Upon receipt your SmartApp should print out the request body. Next, you'll need to issue an HTTP GET request to the provided confirmationUrl. This can be done by simply copy/pasting the confirmationUrl into a browser search bar.

The provided confirmationUrl is only valid for a short time. It can manually be resent at anytime via the Dev Workspace, or by making the following HTTP call:


    curl --request PUT \
    --url https://api.smartthings.com/apps/${APP_ID}/register \
    --header "Accept: application/json" \
    --header "Authorization: Bearer ${PAT_TOKEN}" \
    --data '{}'
  

Ping Lifecycle

The ping lifecycle is a deprecated mechanism used for verifying domain ownership. It requires the Webhook SmartApp to be fully available at the time of registration. During registration the Webhook SmartApp must correctly respond to the challenge in sync to initial request.

Authorizing calls from SmartThings

HTTP Signatures

All requests sent by SmartThings are digitally signed in accordance with the IETF HTTP Signatures 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.

Authorization Flow

Currently, SmartThings provides 2 mechanisms for which signatures are generated.

  • Using a publicly available SmartThings generated x.509 certifcate.
  • Using the public / private key generated during SmartApp registration.

The following diagram outlines the general flow for both signing mechanisms.

alt text

  1. Request made by SmartThings to your SmartApp.
    
        Authorization: Signature keyId="",signature="",headers="",algorithm=""
        
  2. Depending on the elected signing mechanism (SmartThings x.509 Certificate or SmartApp Public Key), the keyId field in the Authorization header will vary.
    • If SmartThings x.509 ⟶ SmartApp should call https://key.smartthings.com + <aKeyId> to fetch the correct public key for signature verification.
    • If SmartThings Public Key ⟶ Fetch public key via the mechanism you implemented to store. This is same public key provided during registration.
  3. SmartApp computes the validity of the signature using the resolved key combined with the HTTP Headers provided on callback request.

Using SmartThings x.509 Certificate

A Webhook SmartApp will receive requests digitally signed by one of the publicly available SmartThings x.509 certificates.

This approach has the following benefits:

  • Increased security as the certificates are rotated periodically.
  • Ease of use. You are no longer required to deploy copies of your SmartApp's public key alongside your integration.

On each request, the Webhook SmartApp will lookup / cache the certificate referenced by the HTTP Signature keyId attribute. It will then use that certificate to verify the signature was generated by SmartThings.

Using SmartApp Public Key

Using the SmartApp's public key was the original approach for SmartThings callback authorization.

This mechanism requires you to copy the public key you received during SmartApp registration into your SmartApp container, and use it to verify that the signature provided on the Authorization header originated from SmartThings.

Newly created SmartApps will be opted into the above SmartThings x.509 Certificate method. Existing SmartApps will continue to use the public key method documented in this section.
However, they may opt-in at anytime to leveraging SmartThings x.509 Certificate by following the next section.

Opt in your SmartApp

To opt into using the SmartThings x.509 certificate for digital signing, make a simple API call.

You will need a Personal Access Token and your SmartApp's App ID, which can be found in Developer Workspace.

Request

curl --request PUT \
--url https://api.smartthings.com/apps/${YOUR_APP_ID}/signature-type \
--header "Accept: application/json" \
--header "Content-Type: application/json" \
--header "Authorization: Bearer ${PAT_TOKEN}" \
--data '{ "signatureType": "ST_PADLOCK" }' 

Response

202 {}

Additionally, a SmartApp can revert back to using the associated public key:

Request

curl --request PUT \
--url https://api.smartthings.com/apps/${YOUR_APP_ID}/signature-type \
--header "Accept: application/json" \
--header "Content-Type: application/json" \
--header "Authorization: Bearer ${PAT_TOKEN}" \
--data '{ "signatureType": "APP_RSA" }' 

Response

202 {}

The request to change the signature type of your SmartApp is processed asynchronously. It may take up to a few minutes for the change to fully take effect.

Example

The recommended and easiest way to implement the callback authorization logic in your SmartApp is to use one of the official SDKs.

Currently SDKs are available for both NodeJs and Java ecosystems. They can be found on Github @:

The following uses the SmartThings Node SDK.


    
    /**
     * A very simple SmartApp example leveraging the SDK
     * to launch a SmartApp on the Express web framework.
     *
     * All SmartThings callback authorization mechanisms 
     * are implicitly supported through SDK usage.
     */
    const express = require('express');
    const SmartApp = require('@smartthings/smartapp');
    const server = express();
    const PORT = 5555;
    
    server.use(express.json());
    
    const smartapp = new SmartApp()
    // If you do not have it yet, omit publicKey() - i.e. PING lifecycle
    // Usage of '@' symbol informs SDK to fetch from local disk using `fs` package.
    //  .publicKey('@smartthings_rsa.pub')
        .enableEventLogging(2)
        .page('mainPage', (context, page, configData) => {
            page
                .name('SmartApp Authorization Example')
                .complete(true)
                .section('my-section', section => {
                    section
                        .paragraphSetting('my-paragraph')
                        .text('SmartApp Authorization Example')
                        .description('An example of how to authorize incoming SmartThings requests to your SmartApp.')
    
                })
        });
    
    server.post('/', (req, res, next) => {
        console.log(req.header('Authorization'));
        smartapp.handleHttpCallback(req, res)
    });
    
    server.listen(PORT, () => console.log(`Server is up and running on port ${PORT}`));

See also