Skip to content

Commit c463e83

Browse files
CopilotGrantBirki
andcommitted
Add comprehensive documentation for structured header functionality
Co-authored-by: GrantBirki <[email protected]>
1 parent 5323fa2 commit c463e83

File tree

2 files changed

+90
-1
lines changed

2 files changed

+90
-1
lines changed

docs/auth_plugins.md

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,30 @@ The maximum age (in seconds) allowed for timestamped requests. Only used when `t
8282

8383
A template for constructing the payload used in signature generation when timestamp validation is enabled. Use placeholders like `{version}`, `{timestamp}`, and `{body}`.
8484

85-
**Example:** `{version}:{timestamp}:{body}`
85+
**Example:** `{version}:{timestamp}:{body}` (Slack-style), `{timestamp}.{body}` (Tailscale-style)
86+
87+
##### `header_format` (optional)
88+
89+
The format of the signature header content. Use "structured" for headers containing comma-separated key-value pairs.
90+
91+
**Default:** `simple`
92+
**Valid values:**
93+
- `simple` - Standard single-value headers like "sha256=abc123..." or "abc123..."
94+
- `structured` - Comma-separated key-value pairs like "t=1663781880,v1=abc123..."
95+
96+
##### `signature_key` (optional)
97+
98+
When `header_format` is "structured", this specifies the key name for the signature value in the header.
99+
100+
**Default:** `v1`
101+
**Example:** `signature`
102+
103+
##### `timestamp_key` (optional)
104+
105+
When `header_format` is "structured", this specifies the key name for the timestamp value in the header.
106+
107+
**Default:** `t`
108+
**Example:** `timestamp`
86109

87110
#### HMAC Examples
88111

@@ -218,6 +241,59 @@ curl -X POST "$WEBHOOK_URL" \
218241

219242
This approach provides strong security through timestamp validation while using a simpler format than the Slack-style implementation. The signing payload becomes `1609459200:{"event":"deployment","status":"success"}` and the resulting signature format is `sha256=computed_hmac_hash`.
220243

244+
**Tailscale-style HMAC with structured headers:**
245+
246+
This configuration supports providers like Tailscale that include both timestamp and signature in a single header using comma-separated key-value pairs.
247+
248+
```yaml
249+
auth:
250+
type: hmac
251+
secret_env_key: TAILSCALE_WEBHOOK_SECRET
252+
header: Tailscale-Webhook-Signature
253+
algorithm: sha256
254+
format: "signature_only" # produces "abc123..." (no prefix)
255+
header_format: "structured" # enables parsing of "t=123,v1=abc" format
256+
signature_key: "v1" # key for signature in structured header
257+
timestamp_key: "t" # key for timestamp in structured header
258+
payload_template: "{timestamp}.{body}" # dot-separated format
259+
timestamp_tolerance: 300 # 5 minutes
260+
```
261+
262+
**How it works:**
263+
264+
1. The signature header contains both timestamp and signature: `Tailscale-Webhook-Signature: t=1663781880,v1=0123456789abcdef`
265+
2. The timestamp and signature are extracted from the structured header
266+
3. The HMAC is calculated over the payload using the template: `{timestamp}.{body}`
267+
4. For example, if timestamp is "1663781880" and body is `{"event":"test"}`, the signed payload becomes: `1663781880.{"event":"test"}`
268+
5. The signature is validated as a raw hex string (no prefix)
269+
270+
**Example curl request:**
271+
272+
```bash
273+
#!/bin/bash
274+
275+
# Configuration
276+
WEBHOOK_URL="https://your-hooks-server.com/webhooks/tailscale"
277+
SECRET="your_tailscale_webhook_secret"
278+
TIMESTAMP=$(date +%s)
279+
PAYLOAD='{"nodeId":"n123","event":"nodeCreated"}'
280+
281+
# Construct the signing payload (timestamp.body format)
282+
SIGNING_PAYLOAD="${TIMESTAMP}.${PAYLOAD}"
283+
284+
# Generate HMAC signature
285+
SIGNATURE=$(echo -n "$SIGNING_PAYLOAD" | openssl dgst -sha256 -hmac "$SECRET" -hex | cut -d' ' -f2)
286+
STRUCTURED_SIGNATURE="t=${TIMESTAMP},v1=${SIGNATURE}"
287+
288+
# Send the request
289+
curl -X POST "$WEBHOOK_URL" \
290+
-H "Content-Type: application/json" \
291+
-H "Tailscale-Webhook-Signature: $STRUCTURED_SIGNATURE" \
292+
-d "$PAYLOAD"
293+
```
294+
295+
This format is particularly useful for providers that want to include multiple pieces of metadata in a single header while maintaining strong security through timestamp validation.
296+
221297
### Shared Secret Authentication
222298

223299
The SharedSecret plugin provides simple secret-based authentication by comparing a secret value sent in an HTTP header. While simpler than HMAC, it provides less security since the secret is transmitted directly in the request header.

lib/hooks/plugins/auth/hmac.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,19 @@ module Auth
3232
# format: "version=signature"
3333
# version_prefix: "v0"
3434
# payload_template: "{version}:{timestamp}:{body}"
35+
#
36+
# @example Configuration for Tailscale-style structured headers
37+
# auth:
38+
# type: HMAC
39+
# secret_env_key: WEBHOOK_SECRET
40+
# header: Tailscale-Webhook-Signature
41+
# algorithm: sha256
42+
# format: "signature_only"
43+
# header_format: "structured"
44+
# signature_key: "v1"
45+
# timestamp_key: "t"
46+
# payload_template: "{timestamp}.{body}"
47+
# timestamp_tolerance: 300 # 5 minutes
3548
class HMAC < Base
3649
# Default configuration values for HMAC validation
3750
#

0 commit comments

Comments
 (0)