Creating Subscription for Microsoft Graph API: Subscription validation request failed - python

I try to create a Subscription for Microsoft Graph API. However, I get the error
Subscription validation request failed. Response must exactly match validationToken query parameter.
The Validation Request looks as follows :
POST /?validationToken=Validation%3a+Testing+client+application+reachability+for+subscription+Request-Id%3a+c69b04df-f3d3-411c-8ceb-7f1ad8b7a927 HTTP/1.1
Using FastApi, the API where validation request is sent to look like
from fastapi import FastAPI
app = FastAPI()
#app.post("/")
def read_call_record(validationToken):
data = {"validationToken": validationToken}
return data
The returned data variable looks like:
{'validationToken': 'Validation: Testing client application reachability for subscription Request-Id: c69b04df-f3d3-411c-8ceb-7f1ad8b7a927'}
Can someone help

Your code needs to Url Decode the validationToken query parameter and return it back to Graph.
From the documentation, your response must happen within 10 seconds with the following properties:
A status code of HTTP 200 OK.
A content type of text/plain.
A body that includes the URL decoded validation token. Simply reflect back the same string that was sent in the validationToken query parameter.
Important: If the client returns an encoded validation token, the validation will fail.

I found the awnser myself. Here function that works:
#app.post("/")
def read_call_record(validationToken):
return Response(content=validationToken, media_type='text/plain')

Related

How can i get Bearer token using basic authentication using python?

I want to get an authorization token using basic authorization. I send a post request using my user name and password but to get the token a body data which is raw text grant_type=client_credentials&scope=Dashboard must contain in the request. but I cannot send the grant_type=client_credentials&scope=Dashboard body data in the post request using python.
#task(1)
def login(self):
self.client.post("/OAuth/Token/", {'Username':'abc', 'Password':'12345'})
self.client.post() returns a Response object. You can see the api at https://requests.readthedocs.io/en/latest/api/#requests.Response
To read out something in the response you can try something like
#task(1)
def login(self):
res = self.client.post("/OAuth/Token/", {'Username':'abc', 'Password':'12345'})
token = res.json()['token']
This attempts to process the Response body as json and pull out the token field. If this doesn't work please provide details on what you are seeing in the response.
Please try this:
In the URL, Append the Grant type and Scope as shown below:
/OAuth/Token?grant_type=client_credentials&scope=Dashboard
It will look like this
self.client.post("/OAuth/Token?grant_type=client_credentials&scope=Dashboard", {'Username':'abc', 'Password':'12345'})

How do I properly format data in a Python POST request to Streamlabs API?

I'm trying to connect our application to Streamlabs' API so we can post donation alerts. To do that, I need to get an access token for the user whose channel we want to alert on. It's a normal OAuth2 thing. We hit the /authorize endpoint and get a code back, which we're then supposed to able to use to get an access token from the /token endpoint (https://dev.streamlabs.com/v1.0/reference#token-1).
But when we send the POST request for the token, we get an error saying the request is missing the "grant_type" parameter.
We're using the normal requests library. I've tried changing the format of the request to requests.post. I've tried altering the data by wrapping it in urlencode and json.dumps. Still no luck.
streamlabs_client_id = config('STREAMLABS_CLIENT_ID')
streamlabs_client_secret = config('STREAMLABS_CLIENT_SECRET')
streamlabs_redirect_uri = config('STREAMLABS_REDIRECT_URI')
grant_type = 'authorization_code'
querydict = {
"grant_type":"authorization_code",
"client_id":streamlabs_client_id,
"client_secret":streamlabs_client_secret,
"redirect_uri":streamlabs_redirect_uri,
"code":code
}
url = "https://streamlabs.com/api/v1.0/token"
streamlabs_response = requests.request("POST", url, data=querydict)
This is the json I get back every time:
{"error":"invalid_request","error_description":"The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Check the \"grant_type\" parameter."}
Any ideas what I'm doing wrong with the data?

Amazon Kinesis Video GetMedia/PutMedia

I used python 3.6 and I want to post video stream to aws kinesis with API.
I used python aws client to create stream and GetDataEndPoint but when I want to post my data with my custom request (PutMedia doesn't include in python client actually), I get an error Unable to determine service/operation name to be authorized.
I've follow the api doc of aws kinesis video media PutMedia and GetMedia.
So I start by getting endpoint with GetDataEndPoint with client method:
response = client.get_data_endpoint( # aws client method
StreamName=STREAM_NAME,
APIName='PUT_MEDIA'
)
end_point = response['DataEndpoint'] # https://s-EXAMPLE.kinesisvideo.eu-west-1.amazonaws.com
and I post my data at this url:
headers = {
"x-amzn-stream-arn": STREAM_ARN,
"x-amzn-fragment-timecode-type": "ABSOLUTE",
"x-amzn-producer-start-timestamp": start_tmstp
}
# Sign header...
response = requests.post(end_point, data=data, headers=headers) # 403 - Unable to determine service/operation name to be authorized
So I don't understand why I get this error... I've found this troubleshooting on aws doc. But they say we must specify ApiName parameter. What I do...
This error might occur if the endpoint is not properly specified. When you are getting the endpoint, be sure to include the following parameter in the GetDataEndpoint call, depending on the API to be called:
I'm also wondering if the GetMedia method is actually implemented in client as they say here because when I debug this method, client don't call GetDataEndPoint and so make request at https://kinesisvideo.region.amazonaws.com insteed of https://ID_EXAMPLE.kinesisvideo.region.amazonaws.com. So method get error Unable to determine service/operation name to be authorized as explained in troubleshooting
The error you're getting is because you're probably providing the endpoint without the "action" that in your case would be putMedia.
Try to append /putMedia to your endpoint and don't forget to specify the "content-type": "application/json" header.
Btw you have also to generate the v4 signatures for your request. You can use a lib or follow this python guide to do it.

How to increase time of office 365 push notification web hook verification

According to microsoft Document I have to follow below steps:
If the listener service successfully validates the URL, it returns a
success response within 5 seconds as follows:
Sets the content type in the response header to text\plain.
Includes the same validation token in the response body.
Returns an HTTP 200 response code. The listener can discard the validation token subsequently.
My enpoint is look like this:
#app.route('/outlook/push', methods=['POST'])
def outlook_push():
return (request.args.get('validationtoken'), 200, {'Content-Type': 'plain/text'})
but this exceeds the time limit(5s)
I am getting error like this:
{'error': {'code': 'ErrorInvalidParameter', 'message': "Notification URL 'https://5cbae04e.ngrok.io/outlook/push?validationtoken=NmIzZDJiMTMtZjhmNy00ZWMwLTg1MDctNDQwMDQ0OWM2NmE1' verification failed 'System.Net.WebException: The operation has timed out\r\n at System.Net.HttpWebRequest.GetResponse()\r\n at Microsoft.Exchange.OData.Model.Notifications.PushNotification.PushSubscriptionCallbackUrlValidationHelper.SendRequestAndVerifyResponse(Uri callbackUrl, PushSubscription pushSubscription)'."}}
Is there anyway to increase time limit?
I don't think it can be changed, and your problem probably is that your route is defined to accept POST method. And office365 is making GET request in there :)

Post print dictionary/json returns error to client

I am sending post request in the body of some json data, to process on server and I want the results back to client(c++ app on phone) in the form of json data and hence parse on mobile.
I have the following code inside handler:
class ServerHandler(tornado.web.RequestHandler):
def post(self):
data = tornado.escape.json_decode(self.request.body)
id = data.get('id',None)
#process data from db (take a while) and pack in result which is dictinary
result = process_data(id)# returns dictionary from db= takes time
print 'END OF HANDLER'
print json.dumps(result)
#before this code below I have tried also
#return result
#return self.write(result)
#return self.write(json.dumps(result))
#return json.dumps(result)
self.set_header('Content-Type', 'application/json')
json_ = tornado.escape.json_encode(result)
self.write(json_)
self.finish()
#return json.dumps(result)
I always get printed 'END OF HANDLER' and valid dictinary/json below on console but when I read at client mobile I always get
<html><title>405: Method Not Allowed</title><body>405: Method Not Allowed</body></html>
Does anyone have any idea what is the bug ?
(I am using CIwGameHttpRequest for sending request and it works when file is static =>name.json but now same content is giving error in post request. )
The error (HTTP 405 Method Not Allowed) means that you have made a request to a valid URL, but you are using an HTTP verb (e.g. GET, POST, PUT, DELETE) that cannot be used with that URL.
Your web service code appears to handle the POST verb, as evidenced by the post method name, and also by the fact that incoming requests appear to have a request body. You haven't shown us your C++ client code, so all I can do is to speculate that it is making a GET request. Does your C++ code call Request->setPOST();? (I haven't worked with CIwGameHttpRequest before, but Googling for it I found this page from which I took that line of code.)
I've not worked with Tornado before, but I imagine that there is some mechanism somewhere that allows you to connect a URL to a RequestHandler. Given that you have a 405 Method Not Allowed error rather than 404 Not Found, it seems that however this is done you've done it correctly. You issue a GET request to Tornado for the URL, it determines that it should call your handler, and only when it tries to use your handler it realises that it can't handle GET requests, concludes that your handler (and hence its URL) doesn't support GETs and returns a 405 error.

Categories