Heroku API returns 403 in Python only - python

So I am working on a Python script to communicate with the Heroku API to get dyno information, but it doesn't seem to work in Python. However, with the exact same information, it works fine in cURL:
Works (cURL 7.51.0):
curl -XGET -H 'Authorization: Bearer <BEARER>' -H 'Accept: application/vnd.heroku+json; version=3' 'https://api.heroku.com/apps/<APP>/dynos/<DYNO>'
Fails (Python, both on 2.7.12, 3.5.3, and 3.6.1):
import json
import requests
callapi = requests.get('https://api.heroku.com/apps/<APP>/dynos/<DYNO>', headers={"Authorization":"Bearer <BEARER>", "Accept":"application/vnd.heroku+json; version=3"})
json = callapi.json()
print(json)
...with error:
{'id': 'forbidden', 'message': 'You do not have access to the app <APP>.'}
Where <APP> is my app name, <DYNO> is the dyno name, and <BEARER> is my bearer token.
Any help would be appreciated!

The problem is that requests uses the .netrc file if no auth argument is provided: http://docs.python-requests.org/en/master/user/authentication/?highlight=netrc#netrc-authentication
So requests is using your Heroku credentials (heroku login saves your credentials in that file).
An easy way to fix the issue is expained here: http://docs.python-requests.org/en/master/user/authentication/?highlight=netrc#new-forms-of-authentication
TL;DR: remove the Authorization header and use the auth parameter with a custom class.
This is the implementation I'm using:
class HerokuBearerAuth(requests.auth.AuthBase):
def __init__(self, api_key):
self.api_key = api_key
def __call__(self, r):
r.headers.update({'Authorization': 'Bearer {}'.format(self.api_key)})
return r
myHeaders = {'Accept': 'application/vnd.heroku+json; version=3'}
response = requests.get(myUrl, headers=myHeaders, auth=HerokuBearerAuth(api_key))

Related

API authentication with python request

I am testing some APIs whose only documentation is the response to the requests for the respective APIs. Basically when I execute I get for all the requests: {"detail":"Authentication credentials were not provided."} except for the login request which is successful, this is because I obviously pass the parameters to it as required I guess.
Below is my code for the requests:
import requests
credential = {'identity' : 'xxxxxxx', 'password': 'xxxxxx'}
#use the 'auth' parameter to send requests with HTTP Basic Auth: auth = ('xxxxxx', 'xxxxxxx')
#url list
api_login = 'https://xxxxxxxx/api/login'
api_channel = 'https://xxxxxxxx/api/channel'
#requests
r_login = requests.post(url=api_login, data = credential)
print(r_login.status_code)
r_channels = requests.get(url=api_channel)
print(r_channels.text)
If it can help, following the info for the API that fail the authentication:
Curl
curl -X 'GET' \
'https://xxxxxxx/api/channels' \
-H 'accept: application/json' \
-H 'X-CSRFToken: xxxxxxxxx'
Request URL
https://xxxxxxx/api/channels
At the moment I've tried using basic authentication in the GET request and passing the headers in the documentation curl but as I'm not a bit practical I might have got it wrong.

How to overcome Error 429: Too Many Requests for Twitter API on Heroku server

I'm trying to run an application on Heroku, which does the following request:
curl 'https://api.twitter.com/2/timeline/conversation/{TWEET_ID_PARAMETER}.json?include_profile_interstitial_type=1&include_blocking=1&include_blocked_by=1&include_followed_by=1&include_want_retweets=1&include_mute_edge=1&include_can_dm=1&include_can_media_tag=1&skip_status=1&cards_platform=Web-12&include_cards=1&include_ext_alt_text=true&include_reply_count=1&tweet_mode=extended&include_entities=true&include_user_entities=true&include_ext_media_color=true&include_ext_media_availability=true&send_error_codes=true&simple_quoted_tweet=true&count=20&ext=mediaStats%2ChighlightedLabel&include_quote_count=true' -H 'authorization: Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA' -H 'x-guest-token: {X_GUEST_TOKEN_PARAMETER}'
To do that, I'm trying to get the x-guest-token with the following Python code:
def obtain_x_guest_token_for_twitter():
data = parse.urlencode({}).encode()
req = Request('https://api.twitter.com/1.1/guest/activate.json', data=data)
req.add_header('Authorization', 'Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA')
req.add_header('User-Agent', 'Firefox')
content = urlopen(req)
x_guest_token = json.load(content)["guest_token"]
return x_guest_token
Where AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA is the public Bearer token
I can make the script run on my local machine, but when I try to run it on my Heroku app it gives me a response of HTTP Error 429: Too Many Requests
Can the heroku public IP be the problem? Maybe blacklisted?
If so, can I change the request to make it work? I have a registered Twitter application, I've tried with application authorization but doesn't work.
Thanks in advance.

Received Authentication Denied as Response while trying to get the access token (for Cloudhub.io) with requests library

I'm tying to get the data from the Cloudhub API which resides on Mulesoft.
I tried to access through postman (With the same Client Credentials - Bearer Authorization) and it's working fine (I can able to get the result with proper get requests).
But when I tried to do the same with Python requests library I ran into issues. Here is my piece of code:
import requests
import json, os
CLIENT_ID = os.environ['CLIENT_ID']
CLIENT_SECRET = os.environ['CLIENT_SECRET']
grant_type = 'client_credentials'
body_params = {'grant_type' : grant_type}
headers = {'Accept': '*/*',
'Cache-Control':'no-cache',
'Accept-Encoding': 'gzip, deflate',
'Content-Type':'application/json, application/x-www-form-urlencoded',
'Connection': 'keep-alive'}
url='https://<domain-name>-api.us-w2.cloudhub.io/api/token'
response = requests.post(url, data=body_params, auth = (CLIENT_ID, CLIENT_SECRET), headers= headers)
token_raw = json.loads(response.text)
print(token_raw)
Result: {'error': 'Authentication denied.'}
All I need to know is
How it's working fine with Postman but why I'm not able to connect with python code?
Is there anything I've to change in my code or any additional information needed for this request? or am I passing the correct endpoint in receiving the access token for Cloudhub API?
Please post your suggestions or any documentation that I need to refer.
Hope the information that I gave is clear and Thanks in Advance !!
I found the answer of my own question. I can get it from the postman itself.
Here is my code for API Call with Python.
import http.client
import os
conn = http.client.HTTPSConnection("<domain-name>-api.us-w2.cloudhub.io")
payload = ''
headers = {
'client_id': os.environ['CLIENT_ID'],
'client_secret': os.environ['CLIENT_SECRET']
}
conn.request("GET", "/api/<Query that you want to pass - endpoint>", payload, headers)
response = conn.getresponse()
resp_data = response.read()
print(resp_data.decode("utf-8"))
The URL is incorrect. To call CloudHub REST API you need to obtain a bearer token from Anypoint Platform REST API. The URL mentioned looks to for some application deployed in CloudHub, not from the platform APIs. This is the same method than to get the bearer token to use in Anypoint MQ Admin API. It looks like you are trying to use the Anypoint MQ Broker API, which is an Anypoint MQ specific token.
Example in Curl to get an Anypoint Platform token:
$ curl -H "Content-Type: application/json" -X POST -d '{"username":"joe.blogs","password":"sample.password"}' https://anypoint.mulesoft.com/accounts/login
{
"access_token": "f648eea2-3704-4560-bb46-bfff79712652",
"token_type": "bearer",
"redirectUrl": "/home/"
}
Additionally the Content-type of your example seems incorrect because it has 2 values.
I'm sure the Postman request is different for it to work, or maybe it works only for the Anypoint MQ Broker API.

Github API returns 401 from python requests but 200 from curl

I'm aware seems a pretty repetitive issue. From bash and curl I make calls to the API Github this way
# curl -u myuser https://api.github.com/repos/myuser/somerepo/pulls?state=all -H "Authorization: token randomtokenhere" -d '{"title":"Pull Request develop to master","base":"master", "head":"develop"}'
and works like a charm. However, from Python 3(3.5.2) with json and requests, I got an error no matter what.
Example:
user = "myuser"
password = "sompassword"
url = "https://api.github.com/repos/myuser/somerepo/pulls?state=all"
token = "randomtokenhere"
title = "Pull Request develop to master"
base = "master"
head = "develop"
headers = {'Authorization': 'token ' + token}
content = {"title":title,"base":base, "head":head}
req = requests.post(url,json=json.dumps(content),auth=(user,password),headers=headers)
print("response posts is {} and status code is {}".format(req.text,req.status_code))
the response of requests is
response posts is {"message":"Must specify two-factor authentication OTP code.","documentation_url":"https://developer.github.com/v3/auth#working-with-two-factor-authentication"} and status code is 401
so it seems the call is just missing the token in some way. But I'm not able to know why. Can I debug this in some way? Or did I miss something very obvious?
Thanks
Well, sorry for bother, my call was not correct. This actually worked:
//req = requests.post(url,json=json.dumps(content),auth=(user,password),headers=headers)
req = requests.post(url,json=content,auth=(user,token))
I've removed the json.dumps function, removed the headers parameter, and instead use password I set up the token with the auth.
Regards

Rest API authentication and access using Python Requests

I have been regularly accessing an API at work using curl. But now i need to do a bit of automation for the same.
Was trying to translate what i do with curl into python using the requests module.
But I keep receiving a 401 error.
My curl requests that i regularly are as below:
Step1: Session Authentication with cookies:
curl -b cookies -c cookies -v -X POST -H "Content-Type: application/json" --data-binary '{"auth":{"username":"aaa","password":"bbb"}}' http://api.xyz.at/auth
Step2: Access API URL for data retrieval
curl -b cookies -c cookies http://api.xyz.at/somepage?per_id=556677
Now using Python Requests, here is what I am doing
Step1: For Authentication
username = 'aaa'
password = 'bbb'
s = requests.Session()
s.post('http://api.xyz.at/auth',auth=('username','pasword'))
This "i think" works fine, and give me the below response
<Response [200]>
Step2: Access API URL for data retrieval
s.get('http://api.xyz.at/somepage?per_id=556677')
but this Step 2 keeps returning an error
<Response [401]>
The code is failing and not sure where.
My Python skills are visibly pedestrian. I have been looking at the Requests website. But unfortunately haven't been able to decipher.
Guidance would be appreciated :)
import urllib2, urllib
url = 'http://api.xyz.at/auth'
pm = urllib2.HTTPPasswordMgrWithDefaultRealm()
pm.add_password(None, url, 'user', 'password')
auth = urllib2.HTTPBasicAuthHandler(pm)
opener = urllib2.build_opener(auth)
urllib2.install_opener(opener)
request = urllib2.Request('http://api.xyz.at/somepage?per_id=556677', None)
handler = urllib2.urlopen(request)
handler.read()
Since you are getting a 401 error I guess you are not passing the authentication token which you get as response from login API. Use the same auth token to perform other options - Get-post-Delete.

Categories

Resources