Authentication of APIs and Webhooks

Learn how to authenticate outbound API calls to Knit using request headers, and how to verify the authenticity of inbound webhook requests from Knit

Overview

This page covers two aspects of authentication in Knit's API:

  • API Authentication - how to authorize requests you make to Knit
  • Webhook Verification - how to verify that incoming requests are genuinely from Knit

Authentication for APIs

Every request to Knit's API must include the following HTTP headers:

HeaderRequiredDescription
AuthorizationYesYour API Key in Bearer format:Bearer <API_KEY>
X-Knit-Integration-IdYesThe integration ID returned by the UI Auth Component, used to identify the source organization and the connected application

Example request headers:

Authorization: Bearer <YOUR_API_KEY>
X-Knit-Integration-Id: <YOUR_INTEGRATION_ID>

Where do I get these?

Your API Key is available on the API Keys page in the Knit dashboard. The Integration ID is returned as a callback when an integration is successful via the Auth flow UI.

Authenticating Webhooks

All POST requests sent by Knit to your server include anX-Knit-Signature key in the header. This signature allows you to verify that the request genuinely originated from Knit and was not tampered with in transit.

How the signature is generated:

Knit computes an HMAC-SHA256 hash of the request payload using your API Key as the secret, then Base64 URL-encodes it (without padding).

To verify a webhook request, follow these steps:

  • Extract the raw request body (payload) as a string.
  • Compute HMAC-SHA256 of the payload using your API_KEY as the secret key.
  • Base64 URL-encode the result (without padding) to get the signature
  • Compare the encoded value against the X-Knit-Signature header in the request.
  • If they match, the request is authentic.


import org.apache.commons.codec.binary.Hex
import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec

val API_KEY = "Your API Key here"
val payload = request.body

val hMacSHA256 = Mac.getInstance("HmacSHA256")
val secretKey = SecretKeySpec(API_KEY..toByteArray(Charsets.UTF_8), "HmacSHA256")
hMacSHA256.init(secretKey)
val encoded = Base64
  .getUrlEncoder().withoutPadding()
  .encodeToString(hMacSHA256.doFinal(toSign.toByteArray(Charsets.UTF_8)))

val isRequestValid = encoded == request.headers["X-Knit-Signature"]
const base64url = require('base64url');
var crypto = require('crypto');

const key = "Your API Key here"

const encoded = base64url(crypto.createHmac("sha256", key).update(request.body).digest());

isRequestValid = encoded == request.headers["X-Knit-Signature"]
import base64
import hashlib
import hmac


def verify_webhook(data, hmac_header, apikey):
  digest = hmac.new(apikey.encode('utf-8'),
                    data.encode('utf-8'),
                    digestmod=hashlib.sha256).digest()

  computed_hmac = base64.urlsafe_b64encode(digest).rstrip(b"=")

  return hmac.compare_digest(computed_hmac, hmac_header.encode('utf-8'))

Note : Always use the raw (unparsed) request body for signature verification. Parsing the body before verification can alter whitespace or key ordering and cause valid signatures to fail.