urequests only working on specific websites - api

I am using a nodemcu esp8266 and the plan is to make a spotify api request to automate playing some songs, and I have a fully functional python script that does exactly that, but when I tried to convert it to upython it failed. I have now spent hours on this and have figured out that the problem is that the urequest for some reason only works on specific websites, for example if I try:
import urequests as requests
x = requests.get('https://www.spotify.com')
print(x.status_code)
i get a 302
but when I try:
import urequests as requests
x = requests.get('https://www.google.com')
print(x.status_code)
I get a 200. That problem percists with a few websites and with no valid response my urequests.put command does not return the things I need... any ideas how to fix it?
thank you in advance.
this is the code I am trying to run:
import urequests as requests
import ujson as json
refresh_token = "xxxxx"
base_64 = "xxxxx"
class Refresh:
def __init__(self):
self.refresh_token = refresh_token
self.base_64 = base_64
def refresh(self):
query = "https://accounts.spotify.com/api/token"
payload={"grant_type": "refresh_token", "refresh_token": refresh_token}
headers={'Authorization': 'Basic %s' % base_64}
data = (json.dumps(payload)).encode()
response = requests.post(query,
data=data,
headers=headers)
print(response.status_code)
print(response.reason)
a = Refresh()
a.refresh()

There are several things going on here that are going to cause your problems.
First, you're trying to send JSON data to the /api/token endpoint:
data = (json.dumps(payload)).encode()
response = requests.post(query,
data=data,
headers=headers)
...but according to the documentation, this endpoint excepts application/x-www-form-urlencoded data.
Second, while the documentation suggests you need to send a basicAuthorization header, in my experiments this evening I wasn't able to get that to work...but I was able to successfully refresh a token if I included the client id and secret in the request body.
You can see my forum post with this question here.
With that in mind, the following code seems to work on my esp8266 running micropython 1.18:
import urequests as requests
refresh_token = "..."
client_id = "..."
client_secret = "..."
class Refresh:
def __init__(self, refresh_token, client_id, client_secret):
self.refresh_token = refresh_token
self.client_id = client_id
self.client_secret = client_secret
def refresh(self):
url = "https://accounts.spotify.com/api/token"
data = "&".join(
[
"grant_type=refresh_token",
f"refresh_token={self.refresh_token}",
f"client_id={self.client_id}",
f"client_secret={self.client_secret}",
]
)
headers = {
"content-type": "application/x-www-form-urlencoded",
}
response = requests.post(url, data=data, headers=headers)
print(data)
print(response.status_code)
print(response.reason)
print(response.text)
a = Refresh(refresh_token, client_id, client_secret)
a.refresh()

Related

How to create quick links with branch io api in python?

I tried following this Creating Quick Links using the Branch HTTP API? , however I think there's been an update where there's no more type 2.
How do you create quick links through branch io api? Here's my current code
import requests
import json
def branch (medium,source,campaign,test,link):
url = "https://api2.branch.io/v1/url"
headers = {'Content-Type': 'application/json'}
data = json.dumps({
"branch_key": '<branch key>',
"channel": f"{source}",
"feature": f"{medium}",
"campaign": f"{campaign}",
"data":{
"$og_title":f"{name}",
"$marketing_title":"test",
"~creation_source":1,
"$og_description":f"{test}",
"~feature":f"{medium}",
"+url":f"https://lilnk.link/{test}",
"$ios_deeplink_path":f"{link}",
"$android_deeplink_path":f"{link}",
"~marketing":'true',
"$one_time_use":'false',
"~campaign":"testing",
"~channel":f"{source}"
})
resp = requests.post(url, headers=headers, data=data)
print(resp.status_code)
This actually gets a 200 code, however I did not find it in the quick links.
I've checked through network where the url is supposed to be https://dashboard.branch.io/v1/link/marketing
and tried using the payload. However 403 error occurs.
How can I create a quicklink?

Cannot POST request using service account key file in Python, getting 'Invalid IAP credentials: Unable to parse JWT', '401 Status Code'

I am trying to send a POST request to a Google App Engine service with a JSON body accompanied by an authorization token. I am generating the access token from a local service account key JSON file. The code below is generating a credential but finally the authorization is being rejected. I also tried different ways already. Even tried writing the request in Postman with a Bearer token in the Header, or even as a plain cURL command. But whatever I try, getting a 401 authentication error. I need to make sure whether the problem is in my side or on the other side with the service. Explored every documentation avaliable but no luck.
from google.auth.transport import requests
from google.oauth2 import service_account
from google.auth.transport.requests import AuthorizedSession
CREDENTIAL_SCOPES = ["https://www.googleapis.com/auth/cloud-platform"]
CREDENTIALS_KEY_PATH = 'my-local-service-account-key-file.json'
#the example service url I am trying to hit with requests
url = 'https://test.appspot.com/submit'
headers = {"Content-Type": "application/json"}
#example data I am sending with the request body
payload = {
"key1": "value 1",
"key2": "value 2"
}
credentials = service_account.Credentials.from_service_account_file(
CREDENTIALS_KEY_PATH,
scopes=CREDENTIAL_SCOPES
)
credentials.refresh(requests.Request())
authed_session = AuthorizedSession(credentials)
response = authed_session.request('POST',
url,
headers=headers,
data=payload
)
#adding some debug lines for your help
print(response.text)
print(response.status_code)
print(response.headers)
Getting the Output:
Invalid IAP credentials: Unable to parse JWT
401
{'X-Goog-IAP-Generated-Response': 'true', 'Date': 'Mon, 03 May 2021 06:52:11 GMT', 'Content-Type': 'text/html', 'Server': 'Google Frontend', 'Content-Length': '44', 'Alt-Svc': 'h3-29=":443"; ma=2592000,h3-T051=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"'}
IAP expects a JWT(OpenID Connect (OIDC)) token in the Authorization header while your method will attach an access token the the Authorization header instead. Take a look at the below code snippet to make a request to an IAP secured resource.
Your code needs to be something like the following:
from google.auth.transport.requests import Request
from google.oauth2 import id_token
import requests
def make_iap_request(url, client_id, method='GET', **kwargs):
"""Makes a request to an application protected by Identity-Aware Proxy.
Args:
url: The Identity-Aware Proxy-protected URL to fetch.
client_id: The client ID used by Identity-Aware Proxy.
method: The request method to use
('GET', 'OPTIONS', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE')
**kwargs: Any of the parameters defined for the request function:
https://github.com/requests/requests/blob/master/requests/api.py
If no timeout is provided, it is set to 90 by default.
Returns:
The page body, or raises an exception if the page couldn't be retrieved.
"""
# Set the default timeout, if missing
if 'timeout' not in kwargs:
kwargs['timeout'] = 90
# Obtain an OpenID Connect (OIDC) token from metadata server or using service
# account.
open_id_connect_token = id_token.fetch_id_token(Request(), client_id)
# Fetch the Identity-Aware Proxy-protected URL, including an
# Authorization header containing "Bearer " followed by a
# Google-issued OpenID Connect token for the service account.
resp = requests.request(
method, url,
headers={'Authorization': 'Bearer {}'.format(
open_id_connect_token)}, **kwargs)
if resp.status_code == 403:
raise Exception('Service account does not have permission to '
'access the IAP-protected application.')
elif resp.status_code != 200:
raise Exception(
'Bad response from application: {!r} / {!r} / {!r}'.format(
resp.status_code, resp.headers, resp.text))
else:
return resp.text
Note: The above method works with implicit credentials that can be set by running command: export GOOGLE_APPLICATION_CREDENTIALS=my-local-service-account-key-file.json to set the path to your service account in the environment and then run the python code from the same terminal.
Take a look at this link for more info.

Is there a way to authenticate OAUTH2.0 of google API through terminal?

I am fetching google photos from my account using Google Photo API. Now there is a need for me to execute that php file via terminal, but the problem is that I can't authenticate with Google API in doing so. Is there a way to do this, and if yes, then how shall it be done?
Yes, it is possible, you need an interactive login for the first authentication but then you can save the token and refresh it automatically as required.
I have implemented this class in Python to do just that.
from requests.adapters import HTTPAdapter
from requests_oauthlib import OAuth2Session
from pathlib import Path
from urllib3.util.retry import Retry
from typing import List, Optional
from json import load, dump, JSONDecodeError
import logging
log = logging.getLogger(__name__)
# OAuth endpoints given in the Google API documentation
authorization_base_url = "https://accounts.google.com/o/oauth2/v2/auth"
token_uri = "https://www.googleapis.com/oauth2/v4/token"
class Authorize:
def __init__(
self, scope: List[str], token_file: Path,
secrets_file: Path, max_retries: int = 5
):
""" A very simple class to handle Google API authorization flow
for the requests library. Includes saving the token and automatic
token refresh.
Args:
scope: list of the scopes for which permission will be granted
token_file: full path of a file in which the user token will be
placed. After first use the previous token will also be read in from
this file
secrets_file: full path of the client secrets file obtained from
Google Api Console
"""
self.max_retries = max_retries
self.scope: List[str] = scope
self.token_file: Path = token_file
self.session = None
self.token = None
try:
with secrets_file.open('r') as stream:
all_json = load(stream)
secrets = all_json['installed']
self.client_id = secrets['client_id']
self.client_secret = secrets['client_secret']
self.redirect_uri = secrets['redirect_uris'][0]
self.token_uri = secrets['token_uri']
self.extra = {
'client_id': self.client_id,
'client_secret': self.client_secret}
except (JSONDecodeError, IOError):
print('missing or bad secrets file: {}'.format(secrets_file))
exit(1)
def load_token(self) -> Optional[str]:
try:
with self.token_file.open('r') as stream:
token = load(stream)
except (JSONDecodeError, IOError):
return None
return token
def save_token(self, token: str):
with self.token_file.open('w') as stream:
dump(token, stream)
self.token_file.chmod(0o600)
def authorize(self):
""" Initiates OAuth2 authentication and authorization flow
"""
token = self.load_token()
if token:
self.session = OAuth2Session(self.client_id, token=token,
auto_refresh_url=self.token_uri,
auto_refresh_kwargs=self.extra,
token_updater=self.save_token)
else:
self.session = OAuth2Session(self.client_id, scope=self.scope,
redirect_uri=self.redirect_uri,
auto_refresh_url=self.token_uri,
auto_refresh_kwargs=self.extra,
token_updater=self.save_token)
# Redirect user to Google for authorization
authorization_url, _ = self.session.authorization_url(
authorization_base_url,
access_type="offline",
prompt="select_account")
print('Please go here and authorize,', authorization_url)
# Get the authorization verifier code from the callback url
response_code = input('Paste the response token here:')
# Fetch the access token
self.token = self.session.fetch_token(
self.token_uri, client_secret=self.client_secret,
code=response_code)
self.save_token(self.token)
# note we want retries on POST as well, need to review this once we
# start to do methods that write to Google Photos
retries = Retry(total=self.max_retries,
backoff_factor=0.1,
status_forcelist=[500, 502, 503, 504],
method_whitelist=frozenset(['GET', 'POST']),
raise_on_status=False)
self.session.mount('https://', HTTPAdapter(max_retries=retries))

GET API code request failure

I just started learning how to use API and I found some really usefull websites and apps like Postman and import.io yet I'm having problems finishing it without help.
I started my little project by getting a working api from import.io (It reads a website and can give you a working API that finds the info in the website)
My REST API looks like this:
https://extraction.import.io/query/runtime/7629f27e-ceee-4ce2-9a1c-cede623d2fc0?_apikey=[apiKey]&url=http%3A%2F%2Fimdb.com
To test and make sure it's working I used postman app and then found a neat feature - code generation.
The app generated this code:
import http.client
conn = http.client.HTTPSConnection("extraction.import.io")
headers = {
'cache-control': "no-cache",
'postman-token': "2087cc79-77b5-0cb9-aa06-adc642978287"
}
conn.request("GET", "/query/runtime/1ac40e3e-f3eb-4290-88c0-e2651b8194a5?_apikey=[apiKey]&url=http%253A%252F%252Fwww.leagueofgraph.com", headers=headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
however the result is:
{
"message" : "Your extraction request has failed.",
"code" : 1003
}
What am I doing wrong?
The code that has been generated has double escaped the "http://"
it should be http%3A%2F%2F not http%253A%252F%252F
Try this corrected code:
import http.client
conn = http.client.HTTPSConnection("extraction.import.io")
headers = {
'cache-control': "no-cache",
'postman-token': "2087cc79-77b5-0cb9-aa06-adc642978287"
}
conn.request("GET", "/query/runtime/1ac40e3e-f3eb-4290-88c0-e2651b8194a5?_apikey=[apiKey]&url=http%3A%2F%2Fwww.leagueofgraph.com", headers=headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))

Why does this Python Reddit API call fail?

If someone could point me in the right direction I would be very grateful. I am trying to use the requests module to interact with Reddit's APIs, but for some reason I am getting HTTP status 403 codes. I am able to successfully log in I believe (since I get HTTP 200), but I cannot perform a successful API request. I am very new to this so please use small words. Thanks.
import requests
import json
from pprint import pprint
# URLs
url_base = r'https://www.reddit.com'
url_login = '/api/login'
url_me = '/api/v1/me'
# Credentials
user = '__kitten_mittens__'
passwd = 'password'
params = {'user': user,
'passwd': passwd,
'api_type': 'json',}
headers = {'user-agent': '/u/__kitten_mittens__ practice api bot'}
# Set up the session/headers
client = requests.session()
client.headers = headers
response = client.post(url_base + url_login, data = params)
j = json.loads(response.content.decode('utf-8'))
mh = j['json']['data']['modhash']
print("The modhash for {USER} is {mh}".format(USER=user, mh=mh))
# THIS CODE GIVES HTTP STATUS CODE 403
response = client.get(url_base + url_me)
me_json = json.loads(r.content.decode('utf-8'))
pprint(me_json)
EDIT: I fixed the missing single quote from the password field. That was not part of the problem.