Skip to content
This repository was archived by the owner on May 24, 2023. It is now read-only.

Commit 185807c

Browse files
author
Tony Bedford
authored
Merge pull request Vonage#68 from Nexmo/tony-verify-webhooks
Shows how to verify signed callbacks and check payload
2 parents f0f57be + 23efd50 commit 185807c

File tree

1 file changed

+62
-0
lines changed

1 file changed

+62
-0
lines changed

messages/verify_signed_webhooks.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import jwt
2+
import hashlib
3+
import json
4+
import os
5+
from flask import Flask, request, jsonify
6+
from os.path import join, dirname
7+
from dotenv import load_dotenv
8+
from pprint import pprint
9+
10+
#Load the environment
11+
envpath = join(dirname(__file__),'../.env')
12+
load_dotenv(envpath)
13+
14+
app = Flask(__name__)
15+
16+
port = os.getenv('PORT')
17+
api_key = os.getenv('NEXMO_API_KEY') # there may be multiple api_key/sig_secret pairs
18+
sig_secret = os.getenv('NEXMO_SIG_SECRET')
19+
20+
@app.route("/webhooks/inbound", methods=['POST'])
21+
def inbound():
22+
# Need token after 'Bearer'
23+
parts = request.headers['authorization'].split()
24+
token = parts[1].strip()
25+
26+
# Extract api_key from token payload
27+
k = jwt.decode(token, verify=False)["api_key"]
28+
# Use k to look up corresponding sig secret
29+
30+
#### 1. Verify request
31+
try:
32+
decoded = jwt.decode(token, sig_secret, algorithms='HS256')
33+
except Exception as e:
34+
print(e)
35+
r = '{"msg": "' + str(e) +'"}'
36+
return (r, 401)
37+
38+
#### 2. Verify payload (only needed if using HTTP rather than HTTPS)
39+
40+
# Obtain transmitted payload hash
41+
payload_hash = decoded["payload_hash"]
42+
43+
# generate hash of request payload
44+
payload = request.data # Obtains request data as binary string
45+
h = hashlib.sha256(payload) # requires binary string
46+
hd = h.hexdigest() # Use hexdigest() and NOT digest()
47+
48+
# Check the payload hash matches the one we created ourselves from request data
49+
if (hd != payload_hash):
50+
return ('{"msg": "Invalid payload"}', 401)
51+
else:
52+
print("Verified payload")
53+
return "OK"
54+
55+
@app.route("/webhooks/status", methods=['POST'])
56+
def status():
57+
data = request.get_json()
58+
return (jsonify(data))
59+
60+
if __name__ == '__main__':
61+
print("Running locally")
62+
app.run(host="localhost", port=port)

0 commit comments

Comments
 (0)