Skip to content

Commit bf1aa5a

Browse files
committed
Fix webhook verification
1 parent 8fd161b commit bf1aa5a

File tree

2 files changed

+22
-23
lines changed

2 files changed

+22
-23
lines changed

examples/webhooks.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,19 +26,21 @@ def mock_webhook_event() -> Tuple[Dict[str, Any], str, str]:
2626
metadata={"progress": 25},
2727
)
2828

29-
signature = create_webhook_signature(
30-
payload=payload.model_dump(),
31-
timestamp=timestamp,
32-
secret=SECRET,
33-
)
34-
3529
evt: Webhook = WebhookAgentTaskStatusUpdate(
3630
type="agent.task.status_update",
3731
timestamp=datetime.fromisoformat("2023-01-01T00:00:00"),
3832
payload=payload,
3933
)
4034

41-
return evt.model_dump(), signature, timestamp
35+
# Create signature from the full event body
36+
evt_dict = evt.model_dump()
37+
signature = create_webhook_signature(
38+
body=evt_dict,
39+
timestamp=timestamp,
40+
secret=SECRET,
41+
)
42+
43+
return evt_dict, signature, timestamp
4244

4345

4446
def main() -> None:

src/browser_use_sdk/lib/webhooks.py

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@
1010

1111
# Models ---------------------------------------------------------------------
1212

13-
# test
14-
1513

1614
class WebhookTestPayload(BaseModel):
1715
"""Test webhook payload."""
@@ -53,20 +51,20 @@ class WebhookAgentTaskStatusUpdate(BaseModel):
5351
# Methods --------------------------------------------------------------------
5452

5553

56-
def create_webhook_signature(payload: Any, timestamp: str, secret: str) -> str:
54+
def create_webhook_signature(body: Any, timestamp: str, secret: str) -> str:
5755
"""
58-
Creates a webhook signature for the given payload, timestamp, and secret.
56+
Creates a webhook signature for the given body, timestamp, and secret.
5957
6058
Args:
61-
payload: The webhook payload to sign
59+
body: The webhook body to sign
6260
timestamp: The timestamp string
6361
secret: The secret key for signing
6462
6563
Returns:
6664
The HMAC-SHA256 signature as a hex string
6765
"""
6866

69-
dump = json.dumps(payload, separators=(",", ":"), sort_keys=True)
67+
dump = json.dumps(body, separators=(",", ":"), sort_keys=True)
7068
message = f"{timestamp}.{dump}"
7169

7270
# Create HMAC-SHA256 signature
@@ -101,8 +99,16 @@ def verify_webhook_event_signature(
10199
else:
102100
json_data = body
103101

104-
# PARSE
102+
# NOTE: Do not use the parsed json_data (model_dump()) for signature verification, use the original json_data (raw body) instead.
103+
# The signature is created from the original body, not the parsed model
104+
calculated_signature = create_webhook_signature(
105+
body=json_data, timestamp=timestamp, secret=secret
106+
)
105107

108+
if not hmac.compare_digest(expected_signature, calculated_signature):
109+
return None
110+
111+
# PARSE
106112
webhook_event: Optional[Webhook] = None
107113

108114
if webhook_event is None:
@@ -121,15 +127,6 @@ def verify_webhook_event_signature(
121127
if webhook_event is None:
122128
return None
123129

124-
# Verify
125-
126-
calculated_signature = create_webhook_signature(
127-
payload=webhook_event.payload.model_dump(), timestamp=timestamp, secret=secret
128-
)
129-
130-
if not hmac.compare_digest(expected_signature, calculated_signature):
131-
return None
132-
133130
return webhook_event
134131

135132
except Exception:

0 commit comments

Comments
 (0)