

# Webhook Security

Each webhook request carries its own signature in the header. Requests are signed with an RSA key pair unique to your account, created when you add your first webhook URL. Validate the signature with your account's public key to confirm the request is authentic.

Your server must accept `POST` requests — all webhook notifications are sent via `POST`.

## Setting Up Your Webhook URL

### igloohome API Partners

Add your webhook URL on the [igloohome API](https://web.igloohome.co/api) portal, in the **Webhooks** section.

### iglooconnect Partners

Email `dev+support@igloohome.co` to get your webhook URL set up — we'll add it right away. An iglooconnect portal for self-service webhook URL management is planned.

## Signature Process

Part of the webhook request is passed through HMAC, and the resulting digest is signed with your account's RSA private key.

## Webhook Request Validation

Given the following HTTPS request:

```
POST /example/path HTTP/1.1
Host: example-host.com
Date: Sat, 20 Jun 2015 12:34:56 GMT
Accept: application/json, text/plain, */*
Content-Type: application/json
Content-Length: 29
User-Agent: igloohome
x-igloocompany-sha256: QA...==

{"payload":"example payload"}
```

The webhook request signature is carried in the `x-igloocompany-sha256` header, base64-encoded.

The body above is shortened. A real body is a JSON event wrapped in `payload`, as shown on [Bridge Events](/home/bridge-events) and [iglooKey Events](/home/iglookey-events).

### Signed Data Construction

Construct the signed data from the following fields, extracted from the request, in order:

- Method (all uppercase)
- Host (hostname only, without port)
- URL Path (without query string)
- Content Type (always `application/json`)
- Date
- Body

Host and URL Path come from your registered webhook URL, which is stored in lowercase.

Concatenate each item, delimited by the bar (`|`) character. For the request above, the final concatenated payload is:

```
POST|example-host.com|/example/path|application/json|Sat, 20 Jun 2015 12:34:56 GMT|{"payload":"example payload"}
```

### HMAC Process

Hash the constructed signed data using HMAC with the SHA-256 hashing algorithm to get the HMAC digest. Use the decoded public key (see [Public Key](#public-key)) as the HMAC key.

### Signature Validation

Decode the signature from the header and verify it against the HMAC digest with your public key. The signature is RSA PKCS#1 v1.5 with SHA-256.

### Public Key

| Property | Value |
| --- | --- |
| Length | 2048 |
| Cipher | RSA |
| Format | DER |
| Type | PKCS1 |

Contact `dev+support@igloohome.co` to request your account's public key. The key you receive is base64-encoded.

## Working Example

The following Node.js example (`crypto` library, v16.x LTS) validates the signature of an example payload with a sample public key:

```javascript
// Using nodejs crypto library.
import * as crypto from 'crypto';

// The example payload that we'll be validating.
const payload = 'POST|example-host.com|/example/path|application/json|Sat, 20 Jun 2015 12:34:56 GMT|{"payload":"example payload"}';

// We use SHA-256 hash algorithm in both the HMAC computation and signature validation.
const hashAlgorithm = 'sha256';

// Decode both the public key string and signature string.
// (Assuming `publicKeyString` and `signatureString` are both valid.)
const publicKey = Buffer.from(publicKeyString, 'base64');
const signature = Buffer.from(signatureString, 'base64');

// Compute the hash using HMAC. The body is hashed as UTF-8 bytes.
const hmacDigest = crypto.createHmac(hashAlgorithm, publicKey)
  .update(payload, 'utf8')
  .digest();

// Validate signature.
const result = crypto.verify(
  hashAlgorithm,
  hmacDigest,
  crypto.createPublicKey({
      key: publicKey,
      format: 'der',
      type: 'pkcs1'
  }),
  signature
);

// Output validation result.
console.log('signature valid:', result); // signature valid: true
```
