You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -4,16 +4,19 @@ An [Otoroshi](https://github.com/MAIF/otoroshi) plugin that validates webhook pa
4
4
5
5
## How it works
6
6
7
-
The plugin is provider-agnostic: the signature header, HMAC algorithmand prefix are all configurable.
7
+
The plugin is provider-agnostic: the signature header, HMAC algorithm, prefix and signing payload template are all configurable.
8
8
9
9
The plugin:
10
10
11
11
1. Reads the raw request body.
12
-
2. Computes `HMAC-<algorithm>(secret, rawBody)` using the configured secret and algorithm.
13
-
3. Prepends the configured prefix to the hex-encoded hash to form the expected signature.
14
-
4. Compares the result (constant-time, to prevent timing attacks) against the configured signature header.
15
-
5. Forwards the request to your backend unchanged when the signature is valid.
16
-
6. Returns **401 Unauthorized** when the signature is missing or invalid.
12
+
2. Optionally resolves a timestamp (from a dedicated header or extracted from the signature header via regex).
13
+
3. Builds the signing payload by applying the `signing_payload_template` (e.g. `{timestamp}.{body}` for Stripe, `v0:{timestamp}:{body}` for Slack, or plain `{body}` for most providers).
14
+
4. Computes `HMAC-<algorithm>(secret, signingPayload)` using the configured secret and algorithm.
15
+
5. Prepends the configured prefix to the hex-encoded hash to form the expected signature.
16
+
6. Optionally extracts the actual signature from the header value using a regex (e.g. `v1=([^,]+)` for Stripe).
17
+
7. Compares the result (constant-time, to prevent timing attacks) against the extracted or raw signature header value.
18
+
8. Forwards the request to your backend unchanged when the signature is valid.
19
+
9. Returns **401 Unauthorized** when the signature is missing, the timestamp cannot be resolved, or the signature is invalid.
17
20
18
21
## Create a route to receive GitHub webhooks
19
22
@@ -81,21 +84,104 @@ $ curl -X POST 'http://otoroshi-api.oto.tools:8080/api/routes' \
81
84
}'
82
85
```
83
86
87
+
## Create a route to receive Stripe webhooks
88
+
89
+
Stripe signs the payload as `{timestamp}.{body}` and sends the signature as `t=<timestamp>,v1=<sig>` in the `Stripe-Signature` header. Both the timestamp and the signature must be extracted from that header with a regex.
90
+
91
+
```shell
92
+
$ curl -X POST 'http://otoroshi-api.oto.tools:8080/api/routes' \
Slack signs the payload as `v0:{timestamp}:{body}` and sends the timestamp in a separate `X-Slack-Request-Timestamp` header. The signature header value is `v0=<sig>`.
128
+
129
+
```shell
130
+
$ curl -X POST 'http://otoroshi-api.oto.tools:8080/api/routes' \
|`prefix`|`string`| no | derived from `algorithm`| String prepended to the hex hash before comparison (e.g. `sha256=`). Defaults are derived automatically from the chosen algorithm. |
164
+
| Field | Type | Required | Default | Description |
|`prefix`|`string`| no | derived from `algorithm`| String prepended to the hex hash before comparison (e.g. `sha256=`). Use `""` when the comparison value is raw hex (Stripe). |
170
+
|`signing_payload_template`|`string`| no |`{body}`| Template for the HMAC input. Supports `{body}` (raw body) and `{timestamp}`. Examples: `{timestamp}.{body}` (Stripe), `v0:{timestamp}:{body}` (Slack). |
171
+
|`timestamp_header`|`string`| no |`""`| Name of a separate HTTP header containing the timestamp (e.g. `X-Slack-Request-Timestamp` for Slack). |
172
+
|`timestamp_extraction_regex`|`string`| no |`""`| Regex with one capture group to extract the timestamp from the **signature header** value (e.g. `t=([^,]+)` for Stripe). |
173
+
|`signature_extraction_regex`|`string`| no |`""`| Regex with one capture group to extract the actual signature from the **signature header** value (e.g. `v1=([^,]+)` for Stripe). When empty the full header value is used. |
92
174
93
175
```json
94
176
{
95
177
"secret": "your-webhook-secret",
96
178
"signature_header": "X-Hub-Signature-256",
97
179
"algorithm": "HmacSHA256",
98
-
"prefix": "sha256="
180
+
"prefix": "sha256=",
181
+
"signing_payload_template": "{body}",
182
+
"timestamp_header": "",
183
+
"timestamp_extraction_regex": "",
184
+
"signature_extraction_regex": ""
99
185
}
100
186
```
101
187
@@ -113,7 +199,8 @@ $ curl -X POST 'http://otoroshi-api.oto.tools:8080/api/routes' \
overridedefdescription:Option[String] =Some("This plugin validates webhook payloads by verifying an HMAC signature. The header name, algorithmand prefix are all configurable.")
111
+
overridedefdescription:Option[String] =Some("This plugin validates webhook payloads by verifying an HMAC signature. The header name, algorithm, prefix and signing payload template are all configurable.")
0 commit comments