> ## Documentation Index
> Fetch the complete documentation index at: https://docs.knoxcall.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Request Signing

> Secure your APIs with HMAC-SHA256 cryptographic signatures. Prevent tampering, replay attacks, and man-in-the-middle attacks.

# Request Signing

Add an extra layer of security to your routes with cryptographic request signing. Verify that requests haven't been tampered with and prevent replay attacks.

## What is Request Signing?

Request signing uses **HMAC-SHA256** (Hash-based Message Authentication Code) to create a cryptographic signature of each request. This signature proves:

* ✅ **Authenticity**: Request came from a trusted source
* ✅ **Integrity**: Request wasn't modified in transit
* ✅ **Non-repudiation**: Sender cannot deny sending the request

## Why Use Request Signing?

### Without Request Signing

```text theme={"dark"}
Attacker intercepts request
    ↓
Modifies payload amount: $10 → $1,000
    ↓
Forwards modified request
    ↓
Your backend processes fraudulent request ❌
```

### With Request Signing

```text theme={"dark"}
Attacker intercepts request
    ↓
Modifies payload amount: $10 → $1,000
    ↓
Signature verification fails ❌
    ↓
Request rejected before reaching backend ✅
```

## How It Works

### Signature Creation (Client Side)

1. **Get current timestamp (Unix seconds):**

```text theme={"dark"}
timestamp = 1640000000
```

2. **Create payload to sign:**

```text theme={"dark"}
payload = "timestamp.requestBody"
Example: "1640000000.{\"orderId\":\"123\",\"amount\":99.99}"
```

3. **Create HMAC-SHA256 signature:**

```text theme={"dark"}
signature = HMAC-SHA256(apiKey, payload)
```

4. **Format signature header:**

```text theme={"dark"}
X-KnoxCall-Signature: t=1640000000,v1=abc123def456...
```

**Format**: `t=<timestamp>,v1=<signature>`

* `t=`: Unix timestamp when request was created
* `v1=`: HMAC-SHA256 signature in hexadecimal

5. **Include in request headers:**

```http theme={"dark"}
X-KnoxCall-Key: your-api-key
X-KnoxCall-Signature: t=1640000000,v1=abc123def456...
```

### Signature Verification (KnoxCall)

1. Extract signature and timestamp from headers
2. Recreate the message from request components
3. Compute expected signature using shared secret
4. Compare signatures:
   * **Match** → Request is valid ✅
   * **Mismatch** → Request is rejected ❌

## Setting Up Request Signing

### Step 1: Enable on Route

1. Navigate to **Routes** → Select your route
2. Scroll to **Security** section
3. Toggle **Require Signature** to ON
4. Configure settings:

**Signature Header:**

```text theme={"dark"}
X-Signature
```

(Default, can be customized)

**Timestamp Header:**

```text theme={"dark"}
X-Timestamp
```

(Default, can be customized)

**Signature Algorithm:**

```text theme={"dark"}
HMAC-SHA256
```

(Most secure and widely supported)

**Timestamp Tolerance:**

```text theme={"dark"}
300 seconds (5 minutes)
```

Allows clock skew between client and server.

5. Click **Save**

### Step 2: Create Signing Secret

1. Navigate to **Secrets** → **Add Secret**
2. Configure:

**Name:**

```text theme={"dark"}
my-signing-secret
```

**Type:**

```text theme={"dark"}
Static Secret
```

**Value:**

```text theme={"dark"}
[Generate a strong random key]
```

**Recommended:** Use a cryptographically secure random string:

```bash theme={"dark"}
openssl rand -hex 32
```

3. Click **Save**

### Step 3: Assign Secret to Client

1. Navigate to **Clients** → Select your client
2. Go to **Signing Configuration** tab
3. Select the signing secret
4. Click **Save**

Now this client must sign all requests to protected routes.

## Client Implementation

### JavaScript/Node.js

```javascript theme={"dark"}
const crypto = require('crypto');

function signRequest(body, apiKey) {
  // 1. Get current timestamp (Unix seconds)
  const timestamp = Math.floor(Date.now() / 1000);

  // 2. Stringify body (use empty string for GET requests)
  const bodyStr = body ? JSON.stringify(body) : '';

  // 3. Create message to sign: "timestamp.body"
  const payload = `${timestamp}.${bodyStr}`;

  // 4. Create HMAC-SHA256 signature
  const signature = crypto
    .createHmac('sha256', apiKey)
    .update(payload)
    .digest('hex');

  // 5. Format signature header: "t=timestamp,v1=signature"
  const signatureHeader = `t=${timestamp},v1=${signature}`;

  return { signatureHeader, timestamp };
}

// Usage
const body = { orderId: '123', amount: 99.99 };
const apiKey = 'your-tenant-api-key'; // Use your KnoxCall API key as signing secret

const { signatureHeader } = signRequest(body, apiKey);

// Make request with signature
fetch('https://your-subdomain.knoxcall.com/api/orders', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'x-knoxcall-route': 'my-route',
    'x-knoxcall-key': apiKey,
    'x-knoxcall-signature': signatureHeader,
  },
  body: JSON.stringify(body),
});
```

### Python

```python theme={"dark"}
import hmac
import hashlib
import time
import json
import requests

def sign_request(body, api_key):
    # 1. Get current timestamp
    timestamp = int(time.time())

    # 2. Stringify body (empty string for GET requests)
    body_str = json.dumps(body) if body else ''

    # 3. Create payload: "timestamp.body"
    payload = f"{timestamp}.{body_str}"

    # 4. Create HMAC-SHA256 signature
    signature = hmac.new(
        api_key.encode(),
        payload.encode(),
        hashlib.sha256
    ).hexdigest()

    # 5. Format signature header: "t=timestamp,v1=signature"
    signature_header = f"t={timestamp},v1={signature}"

    return signature_header

# Usage
body = {'orderId': '123', 'amount': 99.99}
api_key = 'your-tenant-api-key'

signature_header = sign_request(body, api_key)

# Make request with signature
response = requests.post(
    'https://your-subdomain.knoxcall.com/api/orders',
    headers={
        'Content-Type': 'application/json',
        'x-knoxcall-route': 'my-route',
        'x-knoxcall-key': api_key,
        'x-knoxcall-signature': signature_header,
    },
    json=body
)
```

### Go

```go theme={"dark"}
package main

import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/hex"
    "encoding/json"
    "fmt"
    "time"
)

func signRequest(body interface{}, apiKey string) string {
    // 1. Get current timestamp
    timestamp := time.Now().Unix()

    // 2. Stringify body (empty string for GET requests)
    var bodyStr string
    if body != nil {
        bodyJSON, _ := json.Marshal(body)
        bodyStr = string(bodyJSON)
    }

    // 3. Create payload: "timestamp.body"
    payload := fmt.Sprintf("%d.%s", timestamp, bodyStr)

    // 4. Create HMAC-SHA256 signature
    h := hmac.New(sha256.New, []byte(apiKey))
    h.Write([]byte(payload))
    signature := hex.EncodeToString(h.Sum(nil))

    // 5. Format signature header: "t=timestamp,v1=signature"
    signatureHeader := fmt.Sprintf("t=%d,v1=%s", timestamp, signature)

    return signatureHeader
}

// Usage
func main() {
    body := map[string]interface{}{
        "orderId": "123",
        "amount":  99.99,
    }
    apiKey := "your-tenant-api-key"

    signatureHeader := signRequest(body, apiKey)

    // Include in request headers:
    // x-knoxcall-key: apiKey
    // x-knoxcall-signature: signatureHeader
}
```

### PHP

```php theme={"dark"}
<?php

function signRequest($body, $apiKey) {
    // 1. Get current timestamp
    $timestamp = time();

    // 2. Stringify body (empty string for GET requests)
    $bodyStr = $body ? json_encode($body) : '';

    // 3. Create payload: "timestamp.body"
    $payload = $timestamp . '.' . $bodyStr;

    // 4. Create HMAC-SHA256 signature
    $signature = hash_hmac('sha256', $payload, $apiKey);

    // 5. Format signature header: "t=timestamp,v1=signature"
    $signatureHeader = "t={$timestamp},v1={$signature}";

    return $signatureHeader;
}

// Usage
$body = ['orderId' => '123', 'amount' => 99.99];
$apiKey = 'your-tenant-api-key';

$signatureHeader = signRequest($body, $apiKey);

// Make request with signature
$ch = curl_init('https://your-subdomain.knoxcall.com/api/orders');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json',
    'x-knoxcall-route: my-route',
    'x-knoxcall-key: ' . $apiKey,
    'x-knoxcall-signature: ' . $signatureHeader,
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body));
$response = curl_exec($ch);
curl_close($ch);
?>
```

## Signature Verification Process

KnoxCall performs the following checks:

### 1. Timestamp Validation

```text theme={"dark"}
Current Time: 15:30:00
Request Timestamp: 15:28:30
Tolerance: 5 minutes

Time difference: 1.5 minutes ✅ VALID
```

**Rejected if:**

* Timestamp is more than 5 minutes old
* Timestamp is in the future (clock skew)

### 2. Signature Recreation

```text theme={"dark"}
Extract from request:
- Signature header: t=1640000000,v1=abc123def456...
- Body: {"orderId":"123","amount":99.99}

Parse signature header:
- Timestamp (t): 1640000000
- Signature (v1): abc123def456...

Recreate payload:
payload = "1640000000.{\"orderId\":\"123\",\"amount\":99.99}"

Compute expected signature:
HMAC-SHA256(apiKey, payload) = abc123def456...
```

### 3. Signature Comparison

```text theme={"dark"}
Request Signature:  abc123def456...
Expected Signature: abc123def456...

Match? ✅ Request is authentic
```

## Preventing Replay Attacks

Request signing combined with timestamps prevents replay attacks:

```text theme={"dark"}
Attacker intercepts valid request
    ↓
Timestamp: 15:00:00
Signature: abc123... (valid at 15:00:00)
    ↓
Attacker replays request at 15:10:00
    ↓
Timestamp check fails (> 5 minutes old)
    ↓
Request rejected ❌
```

## Replay Attack Window

Request signing uses timestamp validation to prevent replays. A request signed at time T is accepted for `signature_tolerance_sec` seconds (default 300 / 5 minutes). After that window, the same signed request is rejected.

```text theme={"dark"}
Attacker intercepts valid request at T=0
Attacker replays it at T=360 (6 minutes later)
→ Rejected: signature expired (age: 360s, tolerance: 300s)
```

Within the tolerance window, a replay technically passes signature validation — because KnoxCall does not track request nonces. For endpoints where this matters (e.g. idempotency-critical mutations), enforce your own deduplication at the application layer using a request ID or idempotency key.

## Error Responses

### Invalid Signature

```http theme={"dark"}
HTTP/1.1 401 Unauthorized
Content-Type: application/json

{
  "error": "Unauthorized"
}
```

### Timestamp Too Old

```http theme={"dark"}
HTTP/1.1 401 Unauthorized
Content-Type: application/json

{
  "error": "Unauthorized"
}
```

### Missing Headers

```http theme={"dark"}
HTTP/1.1 400 Bad Request
Content-Type: application/json

{
  "error": "Missing signature headers",
  "message": "x-signature and x-timestamp headers are required",
  "required_headers": ["x-signature", "x-timestamp"]
}
```

## Best Practices

### 1. Use Strong Secrets

Generate cryptographically secure signing secrets:

```bash theme={"dark"}
# Good: 64 hex characters (256 bits)
openssl rand -hex 32
```

❌ **Bad:**

* `password123`
* `my-secret-key`
* Short or predictable strings

### 2. Rotate Secrets Regularly

Rotate signing secrets every 90 days:

1. Create new secret
2. Update clients with new secret (gracefully)
3. Support both old and new secrets for 24 hours
4. Remove old secret

### 3. Use HTTPS Always

Request signing protects integrity, but not confidentiality:

```text theme={"dark"}
HTTPS encrypts the entire request (including signature)
Signature prevents tampering after decryption
```

Always use HTTPS + request signing together.

### 4. Include All Relevant Data

Sign everything that matters:

```javascript theme={"dark"}
// Good: Includes body and important headers
const message = `${timestamp}.${method}.${path}.${body}.${contentType}`;

// Bad: Only timestamp
const message = `${timestamp}`;
```

### 5. Handle Clock Skew

Allow 5-minute tolerance for client clock differences:

```text theme={"dark"}
Server Time: 15:30:00
Client Time: 15:29:00 (1 minute behind)

Still accepted ✅
```

## Use Cases

### Payment Processing

```text theme={"dark"}
Route: /api/payments
Require Signature: ON
Reason: Prevent payment amount tampering
```

### Administrative Actions

```text theme={"dark"}
Route: /api/admin/*
Require Signature: ON
Reason: Ensure admin requests are authentic
```

### Webhook Validation

```text theme={"dark"}
Route: /webhooks/external
Require Signature: ON
Reason: Verify webhooks came from real source
```

### High-Value Transactions

```text theme={"dark"}
Routes: /api/transfers, /api/withdrawals
Require Signature: ON
Reason: Prevent unauthorized financial transactions
```

## Troubleshooting

### "Invalid signature" errors

**Check:**

* ✓ Using the correct signing secret
* ✓ Message format matches exactly (order matters)
* ✓ Body is JSON-stringified identically
* ✓ No extra whitespace in headers

**Debug:**
Log the message before signing:

```javascript theme={"dark"}
console.log('Message to sign:', message);
console.log('Signature:', signature);
```

### "Timestamp expired" errors

**Causes:**

* Client clock is out of sync
* Request took too long to reach KnoxCall
* Network latency

**Fix:**

* Sync client clock with NTP
* Increase timestamp tolerance (temporarily for testing)
* Reduce request queuing on client side

### Signature works in test but not production

**Check:**

* ✓ Using production signing secret (not test secret)
* ✓ Correct route configuration in production
* ✓ Client is assigned to production environment

## Next Steps

<CardGroup cols={2}>
  <Card title="Rate Limiting" icon="gauge" href="/advanced/rate-limiting">
    Add rate limits for additional protection
  </Card>

  <Card title="Secret Management" icon="key" href="/essentials/secrets/secrets-overview">
    Learn about managing signing secrets
  </Card>

  <Card title="Client Permissions" icon="shield" href="/security/client-permissions">
    Configure client-level security
  </Card>

  <Card title="OAuth2 Flow" icon="arrow-right-arrow-left" href="/security/oauth2-flow">
    Set up OAuth2 authentication
  </Card>
</CardGroup>

***

<CardGroup cols={2}>
  <Card title="📊 Statistics" icon="chart-line">
    * **Level**: advanced
    * **Time**: 20 minutes
  </Card>

  <Card title="🏷️ Tags" icon="tags">
    `security`, `hmac`, `signatures`, `authentication`, `integrity`
  </Card>
</CardGroup>
