In order to authenticate in Flask with Stormpath, the user sends an access token in the request's header.
headers = {
'Authorization': 'Bearer <token_id>'
}
I validate it with:
authenticator = ApiRequestAuthenticator(application)
uri = 'bla_dont_care.com'
result = authenticator.authenticate(headers=request.headers, http_method='GET', uri=uri, body={}, scopes=[])
is_valid = result.account is not None
The authenticator is not being initiated in every request but saved in memory.
My response time raised from 40ms to 450ms. I read that the Stormpath SDK caches the API calls specifically for this.
Trying to debug this, I did see that the cache get 2 misses per 1 request here. The key it failes to find is https://api.stormpath.com/v1/applications/VJiXDWTWnYdNgrFe9BoI3/accounts/6TGIMWF47DO0XUK96M07XEMG1. It fails to find the resource here.
What account is it looking for? 6TGIMWF47DO0XUK96M07XEMG1 is not the account sent. How can I debug this?
Related
When I run this python script on my PC I get the following error: An error occurred: 404
I have created a Wix Store. (Free plan).
While logged into the Wix Store, I have created API.
Account Settings -> API (https://manage.wix.com/account/api-keys)
From the account settings I have the Account ID, and the API Key, with permissions to read, write, delete, update store items.
I have also gone to https://dev.wix.com/ and created an app there.
This created APP provides OAUTH App ID & App Secret Key.
import requests
# Replace YOUR_APP_SECRET and YOUR_STORE_ID with your actual values
# Not sure which set of credentials to put here, since none worked.
app_secret = 'see_post'
store_id = 'see_post'
headers = {
'accept': 'application/json',
'x-wix-app-secret': app_secret
}
response = requests.get(f'https://api.wix.com/stores/{store_id}/products', headers=headers)
if response.status_code == 200:
products = response.json()
print(products)
else:
print('An error occurred:', response.status_code)
Things that confuse me:
Do I need a Wix Developer account, and then create an APP, and install this app on my wix store. (I have already done this, just created an app, named it, nothing else, and installed it, hoping that I could use the app secret key, and my stores site ID, to retrieve the store products.)
Do I use the APP ID & APP Secret Key in my script? Or do I use the Account ID and Account API that I created in the account of the Wix Store.
Is the store id in the URL of the wix dashboard?
https://manage.wix.com/dashboard/23861c7e-333-333-3333-4a18d5f55da2/
What I wish to accomplish, figure out how to make this script run correctly.
Then I will modify it to do the following:
List
Add/remove products
Change Product attributes such as price, description, etc.
Sync Inventory between Wix, and a local database.
Update 1:
I'm now using this code as provided in the API docs.
import json
import requests
headers = {
'Content-Type': 'application/json',
'Authorization': 'token generated by https://dev.wix.com/api/rest/wix-stores/inventory/query-inventory'
}
data = {
"query": {},
"options": {}
}
response = requests.post('https://www.wixapis.com/stores/v2/inventoryItems/query', headers=headers, data=json.dumps(data))
if response.status_code == 200:
inventory_items = response.json()
print(inventory_items)
else:
print('An error occurred:', response.status_code)
However the auth token is only valid for 10 minutes.
a. How can I regenerate this token from my python script?
b. Do I have to use these temp. tokens? Can't I just use the API key?
Looks to me like you're going about this the hard way. I think a much easier approach would be to use http-functions to expose several endpoints that then use the wix-stores-backend API and the wix-data API to access your product data.
The Task##
A django application that allows users to sign up and once the user clicks on the account activation link, Zoho CRM is receiving the data and a contact is created in the CRM section.
The Problem
I am currently working on an absolute masterpiece - the ZOHO API.
I am struggling to set up the native Python code that uses POST/GET requests.
Regarding the zcrmsdk 3.0.0, I have completely given up on this solution unless somebody can provide a fully functional example. The support simply blames my code.
The documentation I consulted:
https://www.zoho.com/crm/developer/docs/api/v2/access-refresh.html,
https://www.zoho.com/crm/developer/docs/api/v2/insert-records.html
Since the post request in postman API works fine I do not understand why it does not work in python code
My approach
Generate an self-client API code on: https://api-console.zoho.com/
Insert that code on Postman and retrieve the access or refresh token
Use this access token in an add_user_contact function that is defined in the documentation
It works! Response is success and it is in Zoho CRM
The permsissions scope I am using is: ZohoCRM.modules.contacts.ALL, ZohoCRM.users.ALL, ZohoCRM.modules.deals.ALL, ZohoCRM.modules.attachments.ALL, ZohoCRM.settings.ALL, AAAserver.profile.ALL
Picture of Post Man POST REQUEST
My own Code
def authenticate_crm():
"""
access to response object id:
response_object.get('data')[0].get('details').get('id')
"""
url = 'https://accounts.zoho.com/oauth/v2/token'
headers = {
'Content-Type': 'application/x-www-form-urlencoded'
}
# one time self-client token here -
request_body = {
"code": "1000.aa8abec144835ab79b8f9141fa1fb170.8ab194e4e668b8452847c7080c2dd479",
"redirect_uri": "http://example.com/yourcallback",
"client_id": "1000.H95VDM1H9KCXIADGF05E0E1XSVZKFQ",
"client_secret": "290e505ec52685fa62a640d874e6560f2fc8632e97",
" grant_type": "authorization_code"
}
response = requests.post(url=url, headers=headers, data=json.dumps(request_body).encode('utf-8'))
if response is not None:
print("HTTP Status Code : " + str(response.status_code))
print(response.json())
I am essentially struggling to convert the Postman API request to a Python request to get the token as part of the workflow. What am I doing wrong here?
The documentation states: Note: For security reasons, pass the below parameters in the body of your request as form-data. (access-refresh link) but passing it in postman as form-data breaks the call completely.
According to their own documentation (which is convoluted, contradictory and full of outdated screenshots) the authentication key is needed only once.
Once the request from above runs, I would take the response in the third image and use the refresh key to add the contact.
I am also open to a solution with the SDK 3.0.0, if anybody can help.
I solved it!
I have changed this line:
response = requests.post(url=url, headers=headers, data=json.dumps(request_body).encode('utf-8'))
to this and added some return statement:
payload = '1000.6d9411488dcac999f02304d1f7843ab2.e14190ee4bae175debf00d2f87143b19&' \
'redirect_uri=http%3A%2F%2Fexample.com%2Fyourcallback&' \
'client_id=1000.H95VDM1H9KCXIADGF05E0E1XSVZKFQ&' \
'client_secret=290e505ec52685fa62a640d874e6560f2fc8632e97&'\
'grant_type=authorization_code'
response = requests.request(method="POST", url=url, headers=headers, data=payload)
if response is not None:
print("HTTP Status Code : " + str(response.status_code))
# print(response.text)
print(response.json())
# catch access and refresh token
at = response.json().get('access_token')
rt = response.json().get('refresh_token')
return at, rt
I do not understand why that is different but that fixed it and I could retrieve keys from ZOHO.
I'm trying to access Google API services through a headless Linux server using Oauth2. I read through all the answers on this post: How do I authorise an app (web or installed) without user intervention? but none of them showed how to use the refresh token to generate an access token in python. pinnoyyid had a javascript example (https://stackoverflow.com/a/19766913/15713034) that went something like this:
function get_access_token_using_saved_refresh_token() {
// from the oauth playgroundfunction get_access_token_using_saved_refresh_token() {
// from the oauth playground
const refresh_token = "1/0PvMAoF9GaJFqbNsLZQg-f9NXEljQclmRP4Gwfdo_0";
// from the API console
const client_id = "559798723558-amtjh114mvtpiqis80lkl3kdo4gfm5k.apps.googleusercontent.com";
// from the API console
const client_secret = "WnGC6KJ91H40mg6H9r1eF9L";
// from https://developers.google.com/identity/protocols/OAuth2WebServer#offline
const refresh_url = "https://www.googleapis.com/oauth2/v4/token";
let refresh_request = {
body:`grant_type=refresh_token&client_id=${encodeURIComponent(client_id)}&client_secret=${encodeURIComponent(client_secret)}& refresh_token=${encodeURIComponent(refresh_token)}`;,
method: "POST",
headers: new Headers({
'Content-Type': 'application/x-www-form-urlencoded'
})
}
JavaScript isn't really my best language, but I could decipher they were sending a POST request to the google server. So I tried to recreate the request in Python with the requests package:
import requests
result = requests.post("https://www.googleapis.com/oauth2/v4/token", body={'grant_type':'refresh-token', 'client_id':client_id, 'client_secret':client_secret, 'refresh_token': refresh_token}, headers={'Content-Type': 'application/x-www-form-urlencoded'})
And when I look at result it shows it has a 200 status code (success) but when I try to examine the response, there's nothing easy to read and I can't parse the result in JSON to get the access token. The other approach I tried was to spin up a Flask server using Google's suggested code: https://developers.google.com/identity/protocols/oauth2/web-server#python_5 but that doesn't work either because when I try to return the credentials from one of the functions (object that contains the access code) that won't return JSON no matter what. I'd prefer the post request method since it is cleaner and uses less code. Thanks!
In Python, one approach is to use requests-oauthlib to perform the Backend Application Flow. This is useful when you don't have a front-end to redirect someone to, in order to approve fetching a token.
This website (https://community.atlassian.com/t5/Bitbucket-questions/Refresh-Tokens-using-Python-requests/qaq-p/1213162) says solution could be something like this:
import requests
auth = ("<consumer_id>", "<consumer_secret>")
params = {
"grant_type":"refresh_token",
"refresh_token":"<your_refresh_token_here>"
}
url = "https://www.googleapis.com/oauth2/v4/token"
ret = requests.post(url, auth=auth, data=params) #note data=params, not params=params
Since none of the solutions above worked, I had to finally just give up and use a service account.
tl;dr:
I am trying to set headers in a Python HTTP request for the first time and am getting a 404. I would appreciate any help (see bottom).
I have been experimenting with the Twitter API and have not been having much luck. Eventually I am trying to get all of the media (photos) a user has posted (20 or 50 or whatever per fetch)
In my experience with other APIs, this process would go as follows: Get The userID, Make a get request to some endpoint using that userId, get a JSON feed response.
It seems to be much more complicated in Twitter.
For instance, I do not see any URLs where I can attach an access token or client ID. Instead, in their documentation they show a place where I can retrieve my
Comsumer Key, Consumer Secret, Access Token, and, Access Token Secret
If I enter my request URI and "query", it generates an oAuth Signature, which in this case consists of a
Signature base string, Authorization header and cURL command
This is where things get confusing. It says
Important: This will only be valid for a few minutes. Also remember the cURL command will actually execute the request.
So:
Question 1: right away I am wondering how I can use these credentials to retrieve media over an entire day or a weekend if they become invalid only a few minutes later?
Question 2: Using their "exploring API" console, I can test this query (where I am trying to get the user ID for the Ford" twitter account I use GET https://api.twitter.com/1.1/users/lookup.json?screen_name=hyundai
Typing that into the browser alone returns a 404
{"errors": [{"message": "Bad Authentication data","code": 215}]}
But using their little console APP I can pick "O Auth 1 authentication" (using a twitter app I made) and I get the JSON response I want. Examining the request object in the console shows:
GET /1.1/users/lookup.json?screen_name=hyundai HTTP/1.1
Authorization:
OAuth oauth_consumer_key="555SECRET555",oauth_signature_method="HMAC-SHA1",oauth_timestamp="1421370510",oauth_nonce="1869828628",oauth_version="1.0",oauth_token="333DONTHACKMEPLEASE333",oauth_signature="444SECRET444"
Host:
api.twitter.com
X-Target-URI:
https://api.twitter.com
Connection:
Keep-Alive
tl;dr Version:
So, I thought this was the headers object I would need to send from Python (3) to make the identical request. So here is that code:
import urllib.request
header = {
"Authorization" : "OAuth",
"oauth_consumer_key" :"555SECRET555",
"oauth_signature_method": "HMAC-SHA1",
"oauth_timestamp" : "1421362844",
"oauth_nonce":"1201915763",
"oauth_version": "1.0",
"oauth_token":"333CHANGINGTHIS33333",
"oauth_signature":"222CHANGEDTHIS222",
"Host": "api.twitter.com",
"X-Target-URI": "https://api.twitter.com",
"Connection": "Keep-Alive"
}
endpoint = 'https://api.twitter.com/1.1/users/lookup.json?screen_name=hyundai'
q = urllib.request.Request(endpoint, headers=header)
a = urllib.request.urlopen(q)
print(a.read().decode('utf-8'))
But I get a bad, 404 response.
Have I formatted my headers wrong here or is there another way to do this?
If you capture the network traffic from your request (use http not https), you will see that the headers you send are not the same as the header that are expected. This is why you are getting a 404 response.
What you want is something like
header = {
"Authorization": 'OAuth oauth_consumer_key="555SECRET555",oauth_signature_method="HMAC-SHA1",oauth_timestamp="1421362844",oauth_nonce="1201915763",oauth_version="1.0",oauth_token="333CHANGINGTHIS33333",oauth_signature="222CHANGEDTHIS222"',
"Host": "api.twitter.com",
"X-Target-URI": "https://api.twitter.com",
"Connection": "Keep-Alive"
}
Of course, you could always use an OAuth library, such as RAuth or similar, see
Python: OAuth Library for a discussion
I'm implementing a push notifications mechanism for my android app.
Right now I'm trying to run a small test just to see that I manage to send push notifications from a python server via http to GCM, and to recieve it successfuly in an android client.
Client code is exactly as in google's tutorial:
http://developer.android.com/google/gcm/client.html
There's a main activity called DemoActivity which is responsible for registering or retrieving an already existed a registration id, and two classes GcmIntentService and GcmBroadcastReceiver responsible for handling the messags from the GCM server to the app.
Of course, I've set the SENDER_ID correctly, and I do manage to get a registration ID for my client app.
Now for the server:
In the server I always recieve the following error:
HTTP Error 401: Unauthorized
This is my server code:
url = "https://android.googleapis.com/gcm/send"
headers = { 'Content-Type' : 'application/json', 'Authorization': 'key=' + SERVER_API_KEY }
values = { 'registration_ids': [CLIENT_REGID]
, 'data': {'test': 'test} }
data = urllib.urlencode(values)
req = urllib2.Request(url, json.loads(values), headers)
response = urllib2.urlopen(req)
the_page = response.read()
self.response.out.write(the_page)
For security reasons I omitted the server api key and the client registration id (they're hard-coded), but I double and triple checked them and they're correct. Also, I made sure the server API key was formed correctly (Credentials -> Create new key -> Server key) and also made sure "Any IP allowed".
All solutions I found on the internet was related to a mistake in the server api or something like that but I already checked that.
Thanks for helpers!
edit:
added 'key=' in the header, but now I recieve Bad request error (HTTP code 400)
another edit:
changes the values object abit and sent it using json.loads, but not I have this error in the client (means it finally recieves a notification from server!!):
Unable to instantiate receiver GcmBroadcastReceiver
Any ideas? I copied the sample project from google as is, so I don't have any idea what's wrong here.
The auth header should be (note the key= part):
Authorization:key=<your_key_here>
so you should set headers like this:
headers = { 'Content-Type' : 'application/json', 'Authorization': 'key='+SERVER_API_KEY }
I believe the issue is that you're sending urlencoded payload, when telling the server to expect json. Try changing data to a json object, as a string: data ="{ 'registration_ids':...}"