I am learning Python and I am trying to create a playlist using the Spotify web api but get a http 400 error: Error parsing json. I guess it has to do with an incorrect variable type in the token but I am having a really hard time debugging it as I can't figure out a way to see the post request in raw format.
Posting through the API requires authorizing and this is the script I've created for that:
import requests
import base64
requests.packages.urllib3.disable_warnings()
client_id = 'ID'
client_secret = 'SECRET'
redirect_uri = 'http://spotify.com/'
scope = 'playlist-modify-private playlist-read-private'
def request_token():
# 1. Your application requests authorization
auth_url = 'https://accounts.spotify.com/authorize'
payload = {'client_id': client_id, 'response_type':'code','redirect_uri':redirect_uri}
auth = requests.get(auth_url,params = payload)
print '\nPlease go to this url to authorize ', auth.url
# 2. The user is asked to authorize access within the scopes
# 3. The user is redirected back to your specified URI
resp_url = raw_input('\nThen please copy-paste the url you where redirected to: ')
resp_code= resp_url.split("?code=")[1].split("&")[0]
# 4. Your application requests refresh and access tokens
token_url = 'https://accounts.spotify.com/api/token'
payload = {'redirect_uri': redirect_uri,'code': resp_code, 'grant_type': 'authorization_code','scope':scope}
auth_header = base64.b64encode(client_id + ':' + client_secret)
headers = {'Authorization': 'Basic %s' % auth_header}
req = requests.post(token_url, data=payload, headers=headers, verify=True)
response = req.json()
return response
This is the function actually trying to create the playlist using the authorization token (import authorizer is the function above):
import requests
import authorizer
def create_playlist(username, list_name):
token = authorizer.request_token()
access_token = token['access_token']
auth_header = {'Authorization': 'Bearer {token}'.format(token=access_token), 'Content-Type': 'application/json'}
api_url = 'https://api.spotify.com/v1/users/%s/playlists' % username
payload = {'name': list_name, 'public': 'false'}
r = requests.post(api_url, params=payload, headers=auth_header)
But whatever I try it only leads to a 400 error. Can anyone please point out my error here?
Solved by adding a json.dumps for the input: json.dumps(payload) and changing the payload to be 'data' and not 'params' in the request.
So the new functioning request equals:
r = requests.post(api_url, data=json.dumps(payload), headers=auth_header)
Related
I am trying to get this access token with Python. With Postman I can get an access token. After configurations in the screenshots, I click the Get Access Token button, and A pop-up throws for username and password. Then I fill them. After that, I can get an access token from Postman.
To get an access token with Python, I wrote the code below. In the first get request, I get the cookies and Redirect URL(to post user credentials). Then, I post user credentials and cookies to Redirected URL. After that, the response header["location"] must include a code parameter to get the token. But, the header parameter does not have a code parameter. It has an Authorization URL with query parameters. How can get this code parameter? Finally, I will post a request(to token URL) with this code to get an access token on the response body.
import base64
import hashlib
import json
import os
import re
import urllib.parse
import requests
from bs4 import BeautifulSoup
from rich import print
username = 'username '
password = 'password '
client_id = 'xxxxxxxxxxxxxxxxxxxxxxxxxx'
client_secret = 'yyyyyyyyyyyyyyyyyyyyyyyyyy'
prod_url = 'https://url:port'
callback_url = prod_url + '/main/ifsapplications/projection/oauth2/callback'
authorization_url = prod_url + '/openid-connect-provider/idp/authorization'
token_url = prod_url + '/openid-connect-provider/idp/token'
code_challenge_method = "S256" #SHA-256
scope = 'openid'
response_type ='code'
#Add auth data to request headers
#Grant type = authorization code with pkce
#send client credentials in body
code_verifier = base64.urlsafe_b64encode(os.urandom(40)).decode('utf-8')
code_verifier = re.sub('[^a-zA-Z0-9]+', '', code_verifier)
code_challenge = hashlib.sha256(code_verifier.encode('utf-8')).digest()
code_challenge = base64.urlsafe_b64encode(code_challenge).decode('utf-8')
code_challenge = code_challenge.replace('=', '')
resp = requests. Get(
url=authorization_url,
params={
"response_type": response_type,
"client_id": client_id,
"scope": scope,
"redirect_uri": callback_url,
"code_challenge": code_challenge,
"code_challenge_method": code_challenge_method,
},
allow_redirects=False
)
cookie = resp.headers['Set-Cookie']
cookie = '; '.join(c.split(';')[0] for c in cookie. Split(', '))
soup = BeautifulSoup(resp.text, 'html.parser')
form_action = soup. Find('a').text
resp = requests. Post(
url=form_action,
data={
"username": username,
"password": password
},
headers={"Cookie": cookie,
"Referer": form_action},
allow_redirects=False
)
redirect = resp.headers['Location']
print(resp.text)
print(resp.headers)
OUTPUT:
The following code throws a 401 error and the access_token does not get retrieved. It seems like https://www.reddit.com/api/v1/access_token is rejecting the username/password or clientID/Secretkey that I have provided. But all that info is correct, the username and password is absolutely same as the Reddit login details, and the client ID & Secret key are directly a copy-paste from a dev app created here: https://www.reddit.com/prefs/apps
Please suggest what could be wrong
import requests
auth = requests.auth.HTTPBasicAuth('<client_id>', '<client_secret>')
data = {'grant_type': 'password','username': 'username','password': 'password'}
headers = {'User-Agent': 'ApiTest/0.0.1'}
res = requests.post('https://www.reddit.com/api/v1/access_token',auth=auth, data=data, headers=headers)
if "Unauthorized" in res.text:
print('401 error occured')
TOKEN = res.json()['access_token']
headers = {**headers, **{'Authorization': f"bearer {TOKEN}"}}
requests.get('https://oauth.reddit.com/api/v1/me', headers=headers)
Try to change from bearer to Bearer in your headers. You can also remove the **.
Should be something like this:
headers = {'Authorization': f"Bearer {TOKEN}"}
I am trying to request an authorization code as documented here.
I am using Python requests package to do this and have the following example code:
import requests
auth_endpoint = 'https://login.microsoftonline.com/%s/oauth2/authorize?api-version=1.0' % TENANT_ID
payload = {
'client_id': CLIENT_ID,
'response_type': 'code',
'resource': APP_ID_URI,
'redirect_uri': REPLY_URL
}
response = requests.get(url=auth_endpoint, data=payload)
However, when I run the code above, I get back HTML in the body and not the response I'm expecting. It seems like the HTML code is for a login page.
When I take the formatted endpoint URI and plug it into a browser, I am able to get the auth code from the redirect URI. But, is there a way to get this from the body of the response while still using the requests package?
Please use session class of requests module to implement your requirement. Please refer to the following code sample:
import requests
s = requests.Session()
USERNAME = '<username_email>'
PASSWORD = '<userpassword>'
s.auth = (USERNAME, PASSWORD)
TENANT_ID = '<tenant_id>'
# Authorize URL
authorize_url = 'https://login.microsoftonline.com/%s/oauth2/authorize' % TENANT_ID
# Token endpoint.
token_url = 'https://login.microsoftonline.com/%s/oauth2/token' % TENANT_ID
payload = { 'response_type': 'code',
'client_id': '<tenant_id>',
'redirect_uri': 'http://localhost',
'authority' :'authority'
}
response = s.get(authorize_url, params=payload ,allow_redirects=True)
print response
print response.url
Any further concern, please feel free to let me know.
I'm trying to get an oauth request token from the etrade api (sandbox) in Python with this thing:
import requests
from oauthlib.oauth1 import Client
consumer_key = 'foo' # actual key used
consumer_secret = 'bar' # actual secret used
request_url = 'https://etwssandbox.etrade.com/oauth/sandbox/request_token'
client = Client(consumer_key, client_secret = consumer_secret)
uri, headers, body = client.sign(request_url)
add_params = ', realm="", oauth_token= "", oauth_callback="oob"'
headers['Authorization'] += add_params
r = requests.get(url = uri, headers = headers)
print(r.text) # abbreviated resp: " . . . .auth_problem=consumer_key_rejected,oauth_problem_advice=The oauth_consumer_key foo can be used only in SANDBOX environment . . .
The header generated is:
{'Authorization': 'OAuth oauth_nonce="99985873301258063061424248905", oauth_timestamp="1424248905", oauth_version="1.0", oauth_signature_method="HMAC-SHA1", oauth_consumer_key="foo", oauth_signature="A7ZY91UyZz6NfSGmMA5YWGnVM%2FQ%3D", realm="", oauth_token= "", oauth_callback="oob"'}
I have also tried the url: 'https://etwssandbox.etrade.com/oauth/sandbox/rest/request_token'
And I have tried the header without the add_params (it seems to need the blank oauth_token?)
Note: Confusingly, the response periodically comes back: "Http/1.1 400 Bad Request" with exactly the same url/header.
Any idea what I'm doing wrong?
A helpful person at etrade clarified for the doc-challenged that all oauth api requests (whether you are working in the sandbox or not) need to be sent to the main api url: 'https://etws.etrade.com/oauth/{api}'.
It is only after authenticating a session that the sandbox urls should be used: 'https://etwssandbox.etrade.com/{non-oauth-module}/sandbox/rest/{api}'.
In case others are having problems authenticating a session with etrade in python3, this works in the sandbox at least:
from rauth import OAuth1Service
import webbrowser
def getSession():
# Create a session
# Use actual consumer secret and key in place of 'foo' and 'bar'
service = OAuth1Service(
name = 'etrade',
consumer_key = 'foo',
consumer_secret = 'bar',
request_token_url = 'https://etws.etrade.com/oauth/request_token',
access_token_url = 'https://etws.etrade.com/oauth/access_token',
authorize_url = 'https://us.etrade.com/e/t/etws/authorize?key={}&token={}',
base_url = 'https://etws.etrade.com')
# Get request token and secret
oauth_token, oauth_token_secret = service.get_request_token(params =
{'oauth_callback': 'oob',
'format': 'json'})
auth_url = service.authorize_url.format(consumer_key, oauth_token)
# Get verifier (direct input in console, still working on callback)
webbrowser.open(auth_url)
verifier = input('Please input the verifier: ')
return service.get_auth_session(oauth_token, oauth_token_secret, params = {'oauth_verifier': verifier})
# Create a session
session = getSession()
# After authenticating a session, use sandbox urls
url = 'https://etwssandbox.etrade.com/accounts/sandbox/rest/accountlist.json'
resp = session.get(url, params = {'format': 'json'})
print(resp)
Thanks #ethann - this actually still works as of 6/17/2020 with changed urls.
from rauth import OAuth1Service
import webbrowser
service = OAuth1Service(
name = 'etrade',
consumer_key = 'foo',
consumer_secret = 'bar',
request_token_url = 'https://apisb.etrade.com/oauth/request_token',
access_token_url = 'https://apisb.etrade.com/oauth/access_token',
authorize_url = 'https://us.etrade.com/e/t/etws/authorize?key={}&token={}',
base_url = 'https://apisb.etrade.com')
oauth_token, oauth_token_secret = service.get_request_token(params =
{'oauth_callback': 'oob',
'format': 'json'})
auth_url = service.authorize_url.format('foo again', oauth_token)
webbrowser.open(auth_url)
verifier = input('Please input the verifier: ')
session = service.get_auth_session(oauth_token, oauth_token_secret, params = {'oauth_verifier': verifier})
url = 'https://apisb.etrade.com/v1/accounts/list'
resp = session.get(url, params = {'format': 'json'})
print(resp.text)
I am looking on how to use an APIs, more specifically Egnyte's API.
From their documentation, I must first get a oauth2 token, which I was able to get successfully.
Here are their documentation:
https://developers.egnyte.com/docs/read/Getting_Started
https://developers.egnyte.com/docs/User_Management_API_Documentation#Get-User-List
However, I am not sure what to do afterwards. I am trying to use their User management API, which I am suppose to make a call to:
https://{Egnyte Domain}.egnyte.com/pubapi/v2/users
However, how do i use their token for a requests.get call to their api?
Below is my python code, I am using the the Requests Module (http://docs.python-requests.org/en/latest/):
import requests
api_key = 'MY_API_KEY'
username = 'myUserName'
password = 'myPassword'
payload = {
'grant_type': 'password',
'client_id': api_key,
'username': username,
'password': password
}
token = requests.post("https://{Egnyte Domain}.egnyte.com/puboauth/token", params = payload)
print r.text
The response I get is:
{"access_token":"*MYToken","token_type":"bearer","expires_in":-1}
Thanks!
Ah, someone had showed me.
had to do minor adjustments to the script:
r = requests.post("https://{Egnyte Domain}.egnyte.com/puboauth/token", params=payload)
token = r.json()['access_token']
users = requests.get(url, headers={'Authorization': 'Bearer %s' % token})
You need to use the token in the authorization header of requests. The best thing would be to create a persistent connection.
r = requests.post("https://{Egnyte Domain}.egnyte.com/puboauth/token", params=payload)
if r.ok:
access_token = r.json()['access_token']
session = requests.Session()
session.headers['Authorization'] = "Bearer %s" % access_token
users = session.get('https://{Egnyte Domain}.egnyte.com/pubapi/v2/users')
OR
headers = {"Authorization":"Bearer %s" % access_token}
requests.get('https://{Egnyte Domain}.egnyte.com/pubapi/v2/users', headers=headers)