I'm trying to integrate my app with Twilio for SMS service. I would like to get notified each time there is an incoming SMS message.
Here is what I did
1- I define a lambda and ApiGateway with proxy integration
2- I added the endpoint url to the webhook settings in Twilio console
Once I send an SMS to the Twilio number the lambda is indeed triggered and I'm able to process the message.
However, When I try to use the Twilio validator in order to validate the even I keep getting that the event is invalid
Here is the code snippet handling the validation for post reqeust
validator = RequestValidator(<'auth token'>)
post_body_dict = {key: value[0] for key, value in parse_qs(body).items()}
url = <'url as defined in Twilio's console'>
sig = event['headers'].get("X-Twilio-Signature")
is_valid = validator.validate(url, params, sig)
Notes
1 - The body of the request arrives as a string of query params even though it's a POST request (param1=val1¶m2=val2...)
2 - I also tried removing '+' when processing the body string (except the + prefix from the phone numbers)
3 - I also tried get request but then the query params don't arrive as a string of params but a parsed dict.
4 - I only managed to validate the request if I didn't used lambda, then the request had the original query params string from the sender concatenated to the url but I did not manage to replicate this is a lambda environment .
I went over Twilio's documents but it seems to me that when I use GET request I lose the original order of the query params in the lambda even arriving from the api gateway. And regarding post, I have no idea why I'm unable to make it work.
Resources I tried: Cannot Validate Twilio Request in an AWS Lambda Custom Authorizer, Twilio Request Validation always fail for Voice Call (but works for SMS), twilio webhook: fail to validate signature, https://www.twilio.com/docs/messaging/guides/webhook-request, twilio RequestValidator not working in python wsgi
and some others.
With the help of Twilio support I was able to solve the issue (only for POST requests so this is was I will use). The issue was that when getting the url encoded post body, I converted it to a dictionary but without the empty values.
parsed_dict = parse_qs(event["body"])
result_dict = {key: value[0] for key, value in parsed_dict.items()}
What I should have done was
parsed_dict = parse_qs(event["body"], keep_blank_values=True)
result_dict = {key: value[0] for key, value in parsed_dict.items()}
then validator(url=url, params=result_dict , signiture=sig) worked
Regarding GET, I'm still not sure how to make it work with api gateway lambda