Trying to set up a spreadsheet to take in data via an http post. To test it, I set up a simple python script to just send an http request. I dont want to use a specific google api on python or somewhere else, because I want some other people to be able to simply send a request how they would like. So, In my google script I just have:
function doPost(e){
sheet = SpreadsheetApp.getActiveSheet();
range = sheet.getRange(1, 1)
ange.setValue(e.text)
}
In python I simply have:
import requests
if __name__== "__main__":
params = {'Authorization': "Bearer [token]",
'contentType': 'application/json',
'text': "is working?"}
r = requests.post("https://script.google.com/macros/s/[uniquekey]/exec", params)
print(r.status_code, r.reason)
All I get is
"401 Unauthorized"
I've also tried sending this over python as well as running JS in a webserver and through chrome (which i guessed raised security issues). everything gave me the same response. I'm sure I'm just not authorizing properly, but I havent been able to find the correct way to do it. thanks in advance. I'm sure theres some other issues too, but I cant seem to even get access.
How about this modification?
Modified script:
In this modified script supposes as follows.
Web Apps is deployed as
Execute the app as is Me
Who has access to the app is Only myself or Anyone
Your access token can be used for accessing to your Web Apps.
If your access token cannot be used for it, please try to set the Web Apps as follows.
- Execute the app as is Me
- Who has access to the app is Anyone, even anonymous
- In this setting, you can access to Web Apps without the access token.
Python:
import requests
if __name__== "__main__":
params = {
'text': "is working?",
}
headers = {
'Authorization': "Bearer [token]",
}
r = requests.post("https://script.google.com/macros/s/[uniquekey]/exec", data=params, headers=headers)
print(r.status_code, r.reason)
Note:
Please put the access token to the header.
Google Apps Script:
When you modified your script, please redeploy as new version. By this, the latest script is reflected to the Web Apps.
function doPost(e) {
const sheet = SpreadsheetApp.getActiveSheet();
const range = sheet.getRange(1, 1);
range.setValue(e.parameter.text);
return ContentService.createTextOutput("Done.");
}
Note:
By returning ContentService.createTextOutput(), Web Apps returns the status code of 200.
You can retrieve the value of 'text': "is working?" as e.parameter.text.
When you use SpreadsheetApp.getActiveSheet(), the value of e.parameter.text is put to the 1st page of Spreadsheet.
References:
Web Apps
ContentService
In my environment, I could confirm that this modification worked. But if in your environment, this modified scripts didn't work, I'm sorry.
Related
I am using the Requests python module to do RESTFUL POST API calls to create a new item.
PROBLEM: Items are being duplicated. Sometimes 3 of each item get created. No check for existing data is in place in the final api prevent duplication.
GOAL: I want to send data to create a single new item in a third party application called Netbox which is made with Django.
WHAT HAVE I DONE?:
I have tried writing code to check for existing items and it still
makes duplicates.
I have tried set a timer to pause execution of code by 10 seconds until the request is complete.
The process flow looks like this:
Python Backend (Flask) ---> Python Backend (Flask) --> Netbox (Django)
Data Origin sent via Requests ---> Data Netbox Calls (Via PyNetBox) --> Final DataStore
The two backends are hosted in Cloud Foundry while Netbox is spun up on a Linux on Prem Server.
I have a dictionary like below that represents each item I need to create in Netbox.
Ex. payload = {'site':'1', 'device':'switch01'}
I send each piece of data to my middleware backend via a loop to make the final api call to netbox via pynetbox. I am not able to hit netbox directly.
for payload in payloads:
URL = f'{MIDDLEWARE_URL}/netbox/create_item'
print(f'URL is: {URL} | Payload is {payload}')
headers = { 'content-type': 'application/json', 'cache-control': "no-cache"}
proxies={'http' : None, 'https': None}
r = requests.post(URL, data=json.dumps(payload), headers=headers, verify=False, proxies=proxies)
I would appreciate any help as to why this is happening and any best practices to improving my baseline code logic.
All the best,
Faraz
So I figured it out after some more research and it turns out flask was creating two processes and therefore running my functions twice each time.
This was due to debug being true so used this:
app.run(debug=True, use_reloader=False)
This is my python request code.
url = "https://test.com/"
r = requests.get(url, verify=False)
xsrf_token = r.cookies.get("XSRF-TOKEN")
headers = {
'X-XSRF-TOKEN':xsrf_token
}
data = {"account": "O_O#gmail.com", "password": "123123"}
r = requests.post(url+'/app/get/users', verify=False, data = data, headers=headers)
In laravel log, I got
[2019-12-27 16:09:14] local.ERROR: The payload is invalid. {"exception":"[object] (Illuminate\Contracts\Encryption\DecryptException(code: 0): The payload is invalid. at /var/www/html/test/vendor/laravel/framework/src/Illuminate/Encryption/Encrypter.php:195)
[stacktrace]
Have any method to solve that? Thanks.
You can't solve the issue with a static xsrf alone since it's doing its job preventing Cross Site Request Forging wich is exactly what you're doing in that piece of code.
To use a route as an API, the laravel installation needs to be configured that way, so, if needed, a stateless way of authentification is used (jwt for example) instead of the session with xsrf token for post methods.
Basicly if it's not configured to be used as an API, you will not be able to use it as an API.
I have been working on using the powerbi REST API and I haven't been able to properly make use of it. I made use of this and I was able to register an app and get as far as getting an access token, but still I get 401 statuses on my requests.
My major points of confusion are with regards to the app registration:
1) I am trying to read and write data from a python script. Is this a Native-App or a Web Side Server?
2) What is the meaning of the redirect and home urls on the app registration page? I am currently using my localhost:5000 with different /paths. Could this be the source of the issue?
3) My research indicates that there should be some sort of login interaction. I don't have one, is this an indication that something isn't being done properly?
My code is as follows:
import adal
import requests
AUTHORITY_URL = 'https://login.microsoftonline.com/{my_company}.onmicrosoft.com'
RESOURCE = 'https://analysis.windows.net/powerbi/api'
CLIENT_ID = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
CLIENT_SECRET = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
def make_headers(access_token):
return {
'Authorization': "Bearer {}".format(access_token)
}
context = adal.AuthenticationContext(AUTHORITY_URL)
token = context.acquire_token_with_client_credentials(RESOURCE, CLIENT_ID, CLIENT_SECRET)
access_token = token['accessToken']
headers = make_headers(access_token)
url = "https://api.powerbi.com/v1.0/myorg/datasets"
resp = requests.get(url, headers=headers)
As I said above this works to give me an access token though a get a status 401 response on the request and there is no sign in prompt.
Any help/guidance would be tremendously appreciated.
1) In your case you should register a Native app.
2) Native apps has only Redirect URI. Redirect URI gives AAD more details about the specific application it authenticates. For Native apps you should set it to https://login.live.com/oauth20_desktop.srf.
3) It's hard to say why you are getting Unauthorized response. Check what rights you gave to your application - does it has rights to read or write all datasets? Try to decode the access token at https://jwt.io and look at scp - does it contain "Dataset.Read.All" or "Dataset.ReadWrite.All"?
I work at a small company whose mail is hosted through Google. As one of the administrators responsible for managing employee accounts I'm attempting to automate some tasks using Google APIs and one or more dedicated service accounts. I wrote the short Python script below to request an access token according to the documentation Google provides but I continue to get an "invalid_grant" error.
I've done the following:
Logged into the Google Developers Console as the service account and created a project
Created a client ID of type service account
Logged into the Google Admin Console and added client email address and scope URLs I wish the account to have access to
Searches online have yielded answers indicating that either the system time of the machine is off, the limit for refresh tokens has been exceeded or that the client ID instead of the client email has been used. I've synchronized the time on a Windows machine and a Linux machine prior to running the script and the same error appears. I'm not even getting an access token so I doubt the refresh limit has been exceeded. As can be seen below, the iss value is set to the client email address ending with "#developer.gserviceaccount.com".
I suspect that there is something else I am missing and, as I'm new to Python, I suspect it's something embarrassingly simple. Perhaps someone can assist?
import json
import time
import base64
import requests
from datetime import datetime
utc = datetime.utcnow()
iat = time.mktime(utc.timetuple())
exp = iat + 3600
jwt_header = {
"alg":"RS256",
"typ":"JWT"
}
jwt_claim_set = {
"iss":"pleasehelpme#developer.gserviceaccount.com",
"scope":"https://www.googleapis.com/auth/admin.directory.user",
"aud":"https://www.googleapis.com/oauth2/v3/token",
"iat":int(iat),
"exp":int(exp),
"sub":"someadminfrustrated#googleoauth.com"
}
jwt_jws = bytearray(str(jwt_header) + '.' + str(jwt_claim_set))
jwt_unencoded = str(jwt_header) + '.' + str(jwt_claim_set) + '.' + str(jwt_jws)
jwt_encoded = base64.urlsafe_b64encode(str(jwt_unencoded))
url = 'https://www.googleapis.com/oauth2/v3/token'
headers = {
'content-type': 'application/x-www-form-urlencoded'
}
payload = {
'grant_type': 'urn:ietf:params:oauth:grant-type:jwt-bearer',
'assertion': jwt_encoded
}
response = requests.post(url, headers=headers, params=payload)
print response
print response.json()
The output is the following:
<Response [400]>
{u'error_description': u'Bad Request', u'error': u'invalid_grant'}
I would look at the output http and url to make sure, but it does seem like you are having authentication issues.
I ran into a similar, albeit less complicated problem, and couldn't get my Google Developer credentials in through a python script. I ended up using my Chrome browser cookies with this script to get through that part: http://n8henrie.com/2014/05/decrypt-chrome-cookies-with-python/
Makes everything pretty simple:
url = 'http://www.example.com'
s = requests.Session()
cookies = pyCookieCheat.chrome_cookies(url)
s.get(url, cookies = cookies)
I have a weird problem with Flickr OAuth on Google App Engine:
I'm requesting for oauth token and secret from Flickr using the code attached.. it fails most of time when tested on App Engine.. Flickr returns a page saying
"Flickr has the hiccups. We're looking into the problem right now..."
At first I thought it might be the problem with Flickr.. but then if I copied the URL into chrome directly, I could get the oauth token and secret..
So I thought it could be the problem with my code fetching the URL.. but in fact, with the same piece of code, I'm also able to get token and secret at localhost..
Now I'm really confused.. because this used to work perfectly until recently.. is there any update on App Engine dev server that might cause the problem? Please help!!!
url = "http://www.flickr.com/services/oauth/request_token"
params = {
"oauth_timestamp": str(int(time())),
"oauth_signature_method": "HMAC-SHA1",
"oauth_version": "1.0",
"oauth_nonce": sha1(str(random())).hexdigest(),
"oauth_callback": API_CALLBACK,
"oauth_consumer_key": API_KEY,
}
# Setup the Consumer with the key-secret given by Flickr
consumer = oauth2.Consumer(key=API_KEY, secret=API_SECRET)
# Create request
req = oauth2.Request(method="GET", url=url, parameters=params)
# Create signature
signature = oauth2.SignatureMethod_HMAC_SHA1().sign(req, consumer, None)
# Add the Signature to the request
req['oauth_signature'] = signature
h = httplib2.Http()
resp, content = h.request(req.to_url(), "GET")
Update: I changed the code a little bit, keep requesting if I don't get the token (given a max try allowed). It works... still, it is very annoying that I have to write such work-around. Would appreciate if better alternative is available!
You need to use https instead of http (see the comment thread above)