Search code examples
python-3.xamazon-web-servicesaws-lambdadiscorddigital-signature

Unable to verify Discord signature for bot on AWS Lambda Python 3 (Interactions_Endpoint_URL)


I am attempting to validate the signature for my bot application using discord's "INTERACTIONS ENDPOINT URL" in a lambda function running python 3.7. Using the documentation here under the "Security and Authorization" section, I still seem to be unable to get a valid return on the signature, with the exception being triggered each time. I'm unsure which aspect of the validation is incorrect. I am using AWS API Gateway to forward the headers to the lambda function in order to access them. Any help with pointing me in the right direction would be appreciated.

Edit:

Here is the output of the event in lambda for reference. I removed some of the values for security marked by <>.

{'body': {'application_id': '<AppID>', 'id': '<ID>', 'token': '<Token>', 'type': 1, 'user': {'avatar': '4cbeed4cdd11cac74eec2abf31086e59', 'discriminator': '9405', 'id': '340202973932027906', 'public_flags': 0, 'username': '<username>'}, 'version': 1}, 'headers': {'accept': '*/*', 'content-type': 'application/json', 'Host': '<AWS Lambda address>', 'User-Agent': 'Discord-Interactions/1.0 (+https://discord.com)', 'X-Amzn-Trace-Id': 'Root=1-60a570b8-00381f6e26f023df5f9396b1', 'X-Forwarded-For': '<IP>', 'X-Forwarded-Port': '443', 'X-Forwarded-Proto': 'https', 'x-signature-ed25519': 'de8c8e64be2058f40421e9ff8c7941bdabbf501a697ebcf42aa0419858c978e19c5fb745811659b41909c0117fd89430c720cbf1da33c9dcfb217f669c496c00', 'x-signature-timestamp': '1621455032'}}
import json
import os
from nacl.signing import VerifyKey
from nacl.exceptions import BadSignatureError



def lambda_handler(event, context):
    


    # Your public key can be found on your application in the Developer Portal
    PUBLIC_KEY = os.environ['DISCORD_PUBLIC_KEY']
    
    verify_key = VerifyKey(bytes.fromhex(PUBLIC_KEY))
    
    signature = event['headers']["x-signature-ed25519"]
    timestamp = event['headers']["x-signature-timestamp"]
    body = event['body']
    
    try:
        verify_key.verify(f'{timestamp}{body}'.encode(), bytes.fromhex(signature))
    except BadSignatureError:
        return (401, 'invalid request signature')

Solution

  • I was able to diagnose the issue. I was unable to verify the signature because AWS API Gateway was altering the body into JSON before it got to my lambda function. This made the signature verification come up as invalid each time. I solved this by checking Lambda Proxy Integration in the Integration Request section in API Gateway. Lambda Proxy Check Box. This allowed an unaltered body being sent to Lambda, which I could then verify my discord outgoing webhook. Below is my final code.

    import json 
    import os 
    from nacl.signing import VerifyKey 
    from nacl.exceptions import BadSignatureError 
    
    def lambda_handler(event, context):
    
        PUBLIC_KEY = os.environ['DISCORD_PUBLIC_KEY']
        
        verify_key = VerifyKey(bytes.fromhex(PUBLIC_KEY))
        
        signature = event['headers']["x-signature-ed25519"] 
        timestamp = event['headers']["x-signature-timestamp"] 
        body = event['body']
    
        try: 
            verify_key.verify(f'{timestamp}{body}'.encode(), bytes.fromhex(signature))
            body = json.loads(event['body'])
            if body["type"] == 1:
                return {
                 'statusCode': 200, 
                 'body': json.dumps({'type': 1})
             } 
        except (BadSignatureError) as e:
            return {
                 'statusCode': 401, 
                 'body': json.dumps("Bad Signature")
             }