Request Signing
NativeSuite signs requests to your API using HMAC, allowing you to verify that incoming requests are genuinely from NativeSuite. This guide explains the signing scheme and how to verify signatures in your backend.
Why Request Signing?
When NativeSuite fetches data from your API on behalf of a user, you want to be sure the request is legitimate. Request signing provides:
- Authenticity — Confirm the request came from NativeSuite
- Integrity — Verify the request wasn't tampered with in transit
- Replay protection — Timestamps prevent old requests from being replayed
How It Works
- NativeSuite constructs the request to your API endpoint
- It creates a signature using your app's signing secret and the request details
- The signature is included in the request headers
- Your backend verifies the signature before processing the request
Signature Headers
NativeSuite adds these headers to every request to your data source endpoints:
| Header | Description |
|---|---|
X-NativeSuite-Signature | The HMAC-SHA256 signature |
X-NativeSuite-Timestamp | Unix timestamp of when the request was signed |
Verifying the Signature
Step 1: Extract Headers
Pull the signature and timestamp from the request headers.
Step 2: Check Timestamp
Reject requests where the timestamp is more than 5 minutes old to prevent replay attacks:
import time
timestamp = int(request.headers["X-NativeSuite-Timestamp"])
if abs(time.time() - timestamp) > 300:
return Response("Request expired", status=401)Step 3: Construct the Signing String
The signing string is composed of:
{timestamp}.{method}.{path}.{body}timestamp— TheX-NativeSuite-Timestampvaluemethod— HTTP method, uppercase (e.g.,GET)path— The request path (e.g.,/api/stats)body— The request body (empty string for GET requests)
Step 4: Compute the Expected Signature
Use HMAC-SHA256 with your app's signing secret:
import hmac
import hashlib
signing_string = f"{timestamp}.{method}.{path}.{body}"
expected = hmac.new(
signing_secret.encode(),
signing_string.encode(),
hashlib.sha256
).hexdigest()const crypto = require("crypto");
const signingString = `${timestamp}.${method}.${path}.${body}`;
const expected = crypto
.createHmac("sha256", signingSecret)
.update(signingString)
.digest("hex");import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"fmt"
)
signingString := fmt.Sprintf("%s.%s.%s.%s", timestamp, method, path, body)
mac := hmac.New(sha256.New, []byte(signingSecret))
mac.Write([]byte(signingString))
expected := hex.EncodeToString(mac.Sum(nil))Step 5: Compare Signatures
Use a constant-time comparison to prevent timing attacks:
if not hmac.compare_digest(expected, received_signature):
return Response("Invalid signature", status=401)Finding Your Signing Secret
Your app's signing secret is available in the dashboard:
- Navigate to your app → Settings
- Find the Credentials section
- Copy the Signing Secret
You can rotate credentials from the same page if they're ever compromised. After rotation, NativeSuite immediately starts using the new secret.
When to Verify
Signature verification is optional but recommended. Consider your risk model:
- Public endpoints — Verification adds an extra layer of security
- Internal endpoints — May be sufficient to rely on network-level security
- Sensitive data — Always verify signatures when serving user-specific or financial data
Troubleshooting
Signature mismatch
- Make sure you're using the correct signing secret (not the app ID or API key)
- Check that your signing string construction matches the format exactly
- Ensure the body matches byte-for-byte (watch for encoding differences)
Timestamp rejection
- Clock skew between your server and NativeSuite — ensure your server's clock is synced (NTP)
- The 5-minute window is a recommendation; adjust based on your needs