http-headerstwiliobasic-authenticationtwilio-api

How to access Twilio media with HTTP Basic Auth


I'm trying to create a Python program that receives an image sent to my Twilio WhatsApp number and sends it to another number.

from flask import Flask, request
from twilio.rest import Client
from twilio.twiml.messaging_response import MessagingResponse

app = Flask(__name__)

# Twilio credentials
account_sid = 'redacted'
auth_token = 'redacted'
client = Client(account_sid, auth_token)

@app.route("/whatsapp", methods=['POST'])
def whatsapp():
    media_msg = request.values.get('NumMedia')

    if int(media_msg) > 0:
        media_url = request.values.get('MediaUrl0')

        message = client.messages.create(
            body="test",
            from_='whatsapp:+19179949274',
            to=f'whatsapp:+16466737627',
            media_url=[media_url],
        )
        print("media message: ", message.sid)


    resp = MessagingResponse()
    msg = resp.message()

    return str(resp)

if __name__ == "__main__":
    app.run(debug=True, port=5001)

Simple enough, but it's not working because in July 2023 Twilio implemented mandatory HTTP Basic Authentication for accessing media (as explained here). Therefore, when I run client.messages.create(), the image isn't being sent since the media_url doesn't contain the necessary auth info. I'm new to REST APIs, so I have no idea how to provide the account SSID and auth token to the media_url. Twilio's documentation is lacking and doesn't have examples of how to do it with the Python library.

I thought that since I provided my auth info in the Client object Client(account_sid, auth_token), I wouldn't have to authenticate the media_url, but I'm starting to think that I was wrong since I tried everything and my code still doesn't work.

How should I change my code to be able to provide the necessary auth info to successfully send the image link?


Solution

  • Ah, I see. This is a scenario in which you want to forward incoming media files.

    The media files are not being sent because the Twilio Messaging API requires a URL that is publicly accessible, and the one you received requires Basic Auth (as you said in the question). The solution is to send an HTTP GET request to that URL and to supply your account credentials. The response contains a URL that is valid for 4-hrs and that doesn't require Basic Auth. Then you can use that URL to send a message.

    import requests
    from base64 import b64encode
    
    # Prepare the basic authentication header
    auth_str = "AC1234:Auth_Toen"
    auth_bytes = auth_str.encode('utf-8')
    auth_b64 = b64encode(auth_bytes).decode('utf-8')
    headers = {'Authorization': 'Basic ' + auth_b64}
    
    # Make the request
    url = "https://api.twilio.com/2010-04-01/Accounts/AC1234/Messages/MM1234/Media/ME1234"
    response = requests.get(url, headers=headers)
    
    print(response.url)
    # This returns a https://mms.twiliocdn.com/-URL that can be used to send outbound messages for 4 hours
    

    From the support page:

    Once HTTP Basic Authentication is enabled, the Twilio Account Sid and Auth Token or API Key will be required for accessing, fetching and downloading any new Programmable Messaging media files created going forward. Requests to fetch your media will redirect you to a secure URL that is only valid for 4 hours. When the url expires after 4 hours, you would need to fetch again the media and retrieve a new short-lived URL that will be available for another 4 hours.