Webhook secure intergration with AWS API Gateway and Lambda Auth | Community
Skip to main content
Question

Webhook secure intergration with AWS API Gateway and Lambda Auth

  • October 11, 2024
  • 3 replies
  • 86 views

Hi there,

 

I’m looking to intergrate Typeform with an AWS API Gateway, and I want to securely receive data from Typeform and not leave the endpoint create for the Typeform webhook exposed.

 

Has anyone had any luck using any of the surgestion from here “https://www.typeform.com/developers/webhooks/secure-your-webhooks/. with Lambda Authorizer?

 

 

 

3 replies

Liz
Community Team
Forum|alt.badge.img+5
  • Tech Community Advocate
  • 14840 replies
  • October 11, 2024

Tagging @mathio and @picsoung in case they have any advice!


  • Author
  • Explorer
  • 1 reply
  • October 11, 2024

Basically I’ve had to rewrite the secure webhook code, to run in Lambda without using fastAPI.

As much as I think my code is ok, to get AWS to pass the payload through with the headers Typeform-Signature. I have to run a method into the ‘Integration Request’ the pass the headers, and I think this is reformatting/encoding the payload.

import json
import hashlib
import hmac
import base64

def lambda_handler(event, context):
    receivedSignature = False
    params = event.get('params')
    payload = json.dumps(event.get('body-json'),separators=(',', ':'))
    payload = str(payload).encode('utf-8')

    print(payload)

    secert = 'mylittlesecertblar/blar/blar='

    if not params:
        return {
            statusCode: 500, 
            body: json.dumps("Internal Operation failed.")
        }

    receivedSignature = params['header']['Typeform-Signature']

    if not receivedSignature:
        return {
            statusCode: 403, 
            body:json.dumps("Permission denied.")

        }

    sha_name, signature = receivedSignature.split('=', 1)


    if sha_name != 'sha256':
        return {
            statusCode: 501, 
            body: json.dumps("Operation not supported.")
        }

    is_valid = verifySignature(signature, payload, secert)

    if(is_valid != True):
        return {
            'statusCode': 403, 
        'body': json.dumps('Invalid signature. Permission Denied.')
        }


    return {
        'statusCode': 200,
        'body': json.dumps('Form Received!'),
    }


def verifySignature(receivedSignature: str, payload, secert):
    new_hmac = hmac.new(secert.encode('utf-8'), payload, hashlib.sha256)
    digest = new_hmac.digest()
    e = base64.b64encode(digest).decode()
    print(secert)
    print(e)
    if(e == receivedSignature):
        return True
    return False
##  See https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html
##  This template will pass through all parameters including path, querystring, header, stage variables, and context through to the integration endpoint via the body/payload
#set($allParams = $input.params())
{
"body-json" : $input.body,
"params" : {
#foreach($type in $allParams.keySet())
    #set($params = $allParams.get($type))
"$type" : {
    #foreach($paramName in $params.keySet())
    "$paramName" : "$util.escapeJavaScript($params.get($paramName))"
        #if($foreach.hasNext),#end
    #end
}
    #if($foreach.hasNext),#end
#end
},
"stage-variables" : {
#foreach($key in $stageVariables.keySet())
"$key" : "$util.escapeJavaScript($stageVariables.get($key))"
    #if($foreach.hasNext),#end
#end
},
"context" : {
    "account-id" : "$context.identity.accountId",
    "api-id" : "$context.apiId",
    "api-key" : "$context.identity.apiKey",
    "authorizer-principal-id" : "$context.authorizer.principalId",
    "caller" : "$context.identity.caller",
    "cognito-authentication-provider" : "$context.identity.cognitoAuthenticationProvider",
    "cognito-authentication-type" : "$context.identity.cognitoAuthenticationType",
    "cognito-identity-id" : "$context.identity.cognitoIdentityId",
    "cognito-identity-pool-id" : "$context.identity.cognitoIdentityPoolId",
    "http-method" : "$context.httpMethod",
    "stage" : "$context.stage",
    "source-ip" : "$context.identity.sourceIp",
    "user" : "$context.identity.user",
    "user-agent" : "$context.identity.userAgent",
    "user-arn" : "$context.identity.userArn",
    "request-id" : "$context.requestId",
    "resource-id" : "$context.resourceId",
    "resource-path" : "$context.resourcePath"
    }
}

 


Liz
Community Team
Forum|alt.badge.img+5
  • Tech Community Advocate
  • 14840 replies
  • October 16, 2024

Wow thanks so much for sharing this, @mr_cf ! 😀


Reply