enter image description here
Currently I am developing a chatbot for my application with django, using a twilio trial account.
The chatbot functions properly with ngrok.io, i.e. when the server is operating locally, which mean that when I send a whatsapp message to the twilio sandbox with operation of simply "python manage.py runserver", he will automatically reply me according to my script.
However, as I started deploying the application using the AWS elastic beanstalk, I found that it is only possible for the sandbox to send out whatsapp message by POST request on the web application, but not capable to respond to POST request sent out from whatsapp.
In what way I can deal with it? Is it related to AWS settings or Twilio settings? Some CORS related issues?
Great thanks in advance.
(Please forgive me if my use of language is not accurate as I am not with computer science background.)
Below is part of the code that I applied.
#csrf_exempt
def message(request):
account_sid = 'xxx'
auth_token = 'xxx'
client = Client(account_sid, auth_token)
client_phone_number = request.POST.get('From').removeprefix("whatsapp:+852")
client_phone_number.removeprefix("+852")
incoming_message = request.POST.get('Body')
conversation_sid = request.POST.get('conversation_sid')
incoming_message = incoming_message.lower()
response = MessagingResponse()
#processing the incoming message to produce the text
resp = "text"
response.message(resp)
return HttpResponse(str(response))
I have tried pasting https://xxxxx-env.yyyyyyy.us-east-1.elasticbeanstalk.com/whatsapp/ to the sandbox configuration cell as shown in the image and it resulted to what I mentioned above. The whatsapp url is set just like typically done for other urls for django, followed by message(request) to process the request sent out from the whatsapp. Any other proper way I can do it?
Related
So, i have this code:
import os
from twilio.rest import Client
xml=f'''
<Response>
<Say language="ru-RU">Здравствуйте, пожалуйста введите код для подтверждения.</Say>
</Response>'''
account_sid = ('AC274461ad47988c753424a3c8735dbcc1')
auth_token =('8ac88e8d5bce419ae3b5cbac4fc255f9')
client = Client(account_sid, auth_token)
call = client.calls.create( twiml=xml,
to='+375336412273',
from_='+12318247004',
)
print(call.sid)
I want to put in xml, that way, so i could put result of (what user typed in) in variable.
I want to do it only with python and twilio.rest, on twilio site i only found how to do it with flask, url and twiml.
Twilio developer evangelist here.
In order to be able to run interactive phone calls, there needs to be a way for your application to give instructions to Twilio, receive responses and then give further instructions. The instructions are the TwiML that you send to Twilio, but the way that Twilio communicates things back to you, like the result of what a user typed during a <Gather>, is via webhooks. Webhooks are HTTP requests from Twilio that include data about the call, like user input, in the body of the request.
To use that data and provide Twilio with further TwiML instructions your application needs to be able to receive HTTP requests and respond with an HTTP response containing the TwiML.
There are example in the Twilio documentation using Flask because Flask is a good way to receive and respond to HTTP requests in Python. You could build an application without a framework like Flask, but you would still need to be able to receive an incoming HTTP request and respond to it.
I've been trying to figure out how to make outbound call to leave a voicemail when answering machine is detected. I'm still in the beginning of the exploration and been trying to follow Twilio example like this. I want to use Python, so I'm copy-pasting the example from Twilio below:
# Download the helper library from https://www.twilio.com/docs/python/install
from twilio.rest import Client
# Your Account Sid and Auth Token from twilio.com/console
# DANGER! This is insecure. See http://twil.io/secure
account_sid = 'your account sid'
auth_token = 'your_auth_token'
client = Client(account_sid, auth_token)
call = client.calls.create(
url='http://demo.twilio.com/docs/voice.xml',
to='+1555123456',
from_='+1501123456'
)
print(call.sid)
In the above code, it seems like Twilio's Python SDK always expects url (publicly available XML file/response) as resource to ping to. I'm wondering if I can build a valid XML (TwiML) file and refer to it in the above client.calls.create(...) call. In other words, how do I make Twilio 'speak' what I designed in my local (on my computer) XML file (if that's even possible)? I only plan to run my Python script from my personal computer on need basis, and I don't have any access to server anywhere.
Thank you in advance for your answer/suggestion!
A publicly accessible URL is a requirement. You can use Twilio Studio or Twilio Serverless Functions if you want Twilio to host your logic so you don't need to expose a public URL.
For development, you can use a tool called Ngrok, which will tunnel the Twilio TwiML request to your private application.
You can find more detail here.
How to test webhooks locally with ngrok - Twilio Tip #6
Well you could test this about by using pythons simple http server. and just have it server that file.
curl http://demo.twilio.com/docs/voice.xml -o voice.xml
python -m SimpleHTTPServer
#run to above commands then
#try using bellow?
call = client.calls.create(
url='http://localhost:8000/voice.xml',
to='+1555123456',
from_='+1501123456'
)
#the file at that location is dead simple
<Response>
<Say voice="alice">Thanks for trying our documentation. Enjoy!</Say>
<Play>http://demo.twilio.com/docs/classic.mp3</Play>
</Response>
I'm having some trouble understanding and implementing the Google Directory API's users watch function and push notification system (https://developers.google.com/admin-sdk/reports/v1/guides/push#creating-notification-channels) in my Python GAE app. What I'm trying to achieve is that any user (admin) who uses my app would be able to watch user changes within his own domain.
I've verified the domain I want to use for notifications and implemented the watch request as follows:
directoryauthdecorator = OAuth2Decorator(
approval_prompt='force',
client_id='my_client_id',
client_secret='my_client_secret',
callback_path='/oauth2callback',
scope=['https://www.googleapis.com/auth/admin.directory.user'])
class PushNotifications(webapp.RequestHandler):
#directoryauthdecorator.oauth_required
def get(self):
auth_http = directoryauthdecorator.http()
service = build("admin", "directory_v1", http=auth_http)
uu_id=str(uuid.uuid4())
param={}
param['customer']='my_customer'
param['event']='add'
param['body']={'type':'web_hook','id':uu_id,'address':'https://my-domain.com/pushNotifications'}
watchUsers = service.users().watch(**param).execute()
application = webapp.WSGIApplication(
[
('/pushNotifications',PushNotifications),
(directoryauthdecorator.callback_path, directoryauthdecorator.callback_handler())],
debug=True)
Now, the receiving part is what I don't understand. When I add a user on my domain and check the app's request logs I see some activity, but there's no usable data. How should I approach this part?
Any help would be appreciated. Thanks.
The problem
It seems like there's been some confusion in implementing the handler. Your handler actually sets up the notifications channel by sending a POST request to the Reports API endpoint. As the docs say:
To set up a notification channel for messages about changes to a particular resource, send a POST request to the watch method for the resource.
source
You should only need to send this request one time to set up the channel, and the "address" parameter should be the URL on your app that will receive the notifications.
Also, it's not clear what is happening with the following code:
param={}
param['customer']='my_customer'
param['event']='add'
Are you just breaking the code in order to post it here? Or is it actually written that way in the file? You should actually preserve, as much as possible, the code that your app is running so that we can reason about it.
The solution
It seems from the docs you linked - in the "Receiving Notifications" section, that you should have code inside the "address" specified to receive notifications that will inspect the POST request body and headers on the notification push request, and then do something with that data (like store it in BigQuery or send an email to the admin, etc.)
Managed to figure it out. In the App Engine logs I noticed that each time I make a change, which is being 'watched', on my domain I get a POST request from Google's API, but with a 302 code. I discovered that this was due to the fact I had login: required configured in my app.yaml for the script, which was handling the requests and the POST request was being redirected to the login page, instead of the processing script.
I am trying to obtain a token from Azure AD from Python client application. I want users to seamlessly authenticate with just a username and password (client_id / secret will be embedded in the app). I registered my app and given it all permissions and hit the "grant permissions" button in the new portal according to this post:
The user or administrator has not consented to use the application - Send an interactive authorization request for this user and resource
I am sending an http post to:
https://login.microsoftonline.com/{tenant_id}/oauth2/token
with the following data:
headers = {
"Content-Type": "application/x-www-form-urlencoded"
}
body = "resource={0}&grant_type=password&username={1}&password={2}&client_id={3}&client_secret={4}&scope=openid".format(app_id_uri,user,password,client_id,client_secret)
I cannot seem to get past this error no matter what I try:
b'{"error":"invalid_grant","error_description":"AADSTS65001: The user or administrator has not consented to use the application with ID \'078c1175-e384-4ac7-9116-efbebda7ccc2\'. Send an interactive authorization request for this user and resource.
Again, my goal:
User enters user / pass and nothing else. App sends user / pass / client_id / client_secret, obtains token.
According to your comment:
The message I'm receiving says to do an interactive request but that is exactly what I'm trying to avoid because this is a python app with no web browser and I'm trying to avoid complexity.
I think you want to build a daemon app or an app only application integrating with Azure AD. You can refer to https://graph.microsoft.io/en-us/docs/authorization/app_only for the general introduction.
Furthermore, you can leverage the ADAL for Python to implement this functionality with a ease. Also, you can refer to client_credentials_sample.py for a quick start.
You should try logging in as an admin to be able to give consent to use the application on your tenant at all.
I created 2 applications in my Azure directory, 1 for my API Server and one for my API client. I am using the Python ADAL Library and can successfully obtain a token using the following code:
tenant_id = "abc123-abc123-abc123"
context = adal.AuthenticationContext('https://login.microsoftonline.com/' + tenant_id)
token = context.acquire_token_with_username_password(
'https://myapiserver.azurewebsites.net/',
'myuser',
'mypassword',
'my_apiclient_client_id'
)
I then try to send a request to my API app using the following method but keep getting 'unauthorized':
at = token['accessToken']
id_token = "Bearer {0}".format(at)
response = requests.get('https://myapiserver.azurewebsites.net/', headers={"Authorization": id_token})
I am able to successfully login using myuser/mypass from the loginurl. I have also given the client app access to the server app in Azure AD.
Although the question was posted a long time ago, I'll try to provide an answer. I stumbled across the question because we had the exact same problem here. We could successfully obtain a token with the adal library but then we were not able to access the resource I obtained the token for.
To make things worse, we sat up a simple console app in .Net, used the exact same parameters, and it was working. We could also copy the token obtained through the .Net app and use it in our Python request and it worked (this one is kind of obvious, but made us confident that the problem was not related to how I assemble the request).
The source of the problem was in the end in the oauth2_client of the adal python package. When I compared the actual HTTP requests sent by the .Net and the python app, a subtle difference was that the python app sent a POST request explicitly asking for api-version=1.0.
POST https://login.microsoftonline.com/common//oauth2/token?api-version=1.0
Once I changed the following line in oauth2_client.py in the adal library, I could access my resource.
Changed
return urlparse('{}?{}'.format(self._token_endpoint, urlencode(parameters)))
in the method _create_token_url, to
return urlparse(self._token_endpoint)
We are working on a pull request to patch the library in github.
For the current release of Azure Python SDK, it support authentication with a service principal. It does not support authentication using an ADAL library yet. Maybe it will in future releases.
See https://azure-sdk-for-python.readthedocs.io/en/latest/resourcemanagement.html#authentication for details.
See also Azure Active Directory Authentication Libraries for the platforms ADAL is available on.
#Derek,
Could you set your Issue URL on Azure Portal? If I set the wrong Issue URL, I could get the same error with you. It seems that your code is right.
Base on my experience, you need add your application into Azure AD and get a client ID.(I am sure you have done this.) And then you can get the tenant ID and input into Issue URL textbox on Azure portal.
NOTE:
On old portal(manage.windowsazure.com),in the bottom command bar, click View Endpoints, and then copy the Federation Metadata Document URL and download that document or navigate to it in a browser.
Within the root EntityDescriptor element, there should be an entityID attribute of the form https://sts.windows.net/ followed by a GUID specific to your tenant (called a "tenant ID"). Copy this value - it will serve as your Issuer URL. You will configure your application to use this later.
My demo is as following:
import adal
import requests
TenantURL='https://login.microsoftonline.com/*******'
context = adal.AuthenticationContext(TenantURL)
RESOURCE = 'http://wi****.azurewebsites.net'
ClientID='****'
ClientSect='7****'
token_response = context.acquire_token_with_client_credentials(
RESOURCE,
ClientID,
ClientSect
)
access_token = token_response.get('accessToken')
print(access_token)
id_token = "Bearer {0}".format(access_token)
response = requests.get(RESOURCE, headers={"Authorization": id_token})
print(response)
Please try to modified it. Any updates, please let me know.