Spotify API authentication with Python - python

I'm trying to authenticate a user in the Spotify API, but it keeps returning me the error code "invalid_client". I'm implementing that on a Python Django solution, that's my code:
headers = {'Authorization': 'Basic '+standard_b64encode(client_id)+standard_b64encode(client_secret)}
r = requests.post('https://accounts.spotify.com/api/token', {'code': code, 'redirect_uri': redirect_uri, 'grant_type': grant_type, 'headers': headers}).json()
Any idea why it's not working?

In spotify api docs it is:
Authorization
Required. Base 64 encoded string that contains the client ID and client secret key. The field must have the format: Authorization: Basic base64 encoded( client_id:client_secret)
So i guess you should do:
import base64
'Authorization' : 'Basic ' + base64.standard_b64encode(client_id + ':' + client_secret)
It's working for me so try it. If it doesn't work my code is:
#staticmethod
def loginCallback(request_handler, code):
url = 'https://accounts.spotify.com/api/token'
authorization = base64.standard_b64encode(Spotify.client_id + ':' + Spotify.client_secret)
headers = {
'Authorization' : 'Basic ' + authorization
}
data = {
'grant_type' : 'authorization_code',
'code' : code,
'redirect_uri' : Spotify.redirect_uri
}
data_encoded = urllib.urlencode(data)
req = urllib2.Request(url, data_encoded, headers)
try:
response = urllib2.urlopen(req, timeout=30).read()
response_dict = json.loads(response)
Spotify.saveLoginCallback(request_handler, response_dict)
return
except urllib2.HTTPError as e:
return e
Hope it helps!

Are you sure you're providing client_id & client_secret in the proper format?
Looking at the docs, it suppose to be separated with :.
Also try to run the same flow with curl first and then replicate with python.

Related

POST method of Powerbi api failing but GET is working (Python)

I'm trying to refresh a dataflow using python. It is working for me in Powershell. I'm not sure if I'm using Python correctly. Using Python, I'm able to do get method working correctly.
Python (get method :-> working)
import requests
groupID = <groupid>
#url = 'https://api.powerbi.com/v1.0/myorg/capacities'
header = {'Authorization': f'Bearer {access_token}','Content-Type':'application/json'}
datasets_request_url = 'https://api.powerbi.com/v1.0/myorg/groups/' + groupID + '/datasets'
response = requests.get(url=datasets_request_url, headers=header)
Python failing (POST Method)
dataflowid = <dataflowid>
dataflowrefresh_url = 'https://api.powerbi.com/v1.0/myorg/groups/' + groupID + '/dataflows/'+dataflowid+'/refreshes'
response = requests.post(url=dataflowrefresh_url, headers=header)
HTTPError: 400 Client Error: Bad Request for url:
PowerShell (POST method working)
$workspaceid = <groupid>
$dataflowid = <dataflowid>
$uri = "https://api.powerbi.com/v1.0/myorg/groups/$workspaceid/Dataflows/$dataflowid/refreshes"
# Build JSON, convert back and forth as we're just defining it as a string.
$json = '{"notifyOption": "MailOnFailure"}' | ConvertFrom-Json
$body = $json | ConvertTo-Json
# Refresh the dataflow
Invoke-RestMethod -Uri $uri -Headers $authHeader -body $body -Method POST -Verbose
If I remove the parameter $body, it fails with error 400. I don't know how to convert the working Powershell api call to Python.
Used the same token generated by below code. POST method worked in Powershell but not in Python, GET worked in both.
context = adal.AuthenticationContext(authority=authority_url,
validate_authority=True,
api_version=None)
token = context.acquire_token_with_client_credentials(resource_url, client_id, client_secret)
access_token = token.get('accessToken')
url = 'https://api.powerbi.com/v1.0/myorg/groups/' + workspaceID + '/dataflows/' +dataflowid+ '/refreshes'
payload= {'refreshRequest': 'y'}
data = json.dumps(payload)
headers = header
response = requests.request("POST", url, headers=headers, data=data)
Using refreshRequest : 'Y' made it work. In powershell, I didn't have to give this parameter.

Python requests token for REST API keeps returning 401 unable to determine proper token format

I have this working in Powershell, but i'm trying to figure out how to get it working in Python. In Powershell i just use
$webclient.Headers.Add("Authorization", "Basic $auth")
with passing to $auth my b64Val of my username and password combo, then getting my token string and again passing it as to the same format using Authorization and Basic with $auth containing my long token string.
However, i keep getting 401 returned over in python trying to fig out how to do the same.. here is my sample python code, the first request to get My_token works fine..
password = 'myPassword'
usrPass = "admin:" + password
b64Val = base64.b64encode(usrPass.encode("ascii")).decode("ascii")
My_token=requests.get("https://10.10.1.2/api/login",headers={"Authorization" : "Basic %s" % b64Val}, verify=False)
token_contents = My_token.content.decode("utf-8").replace('"', '')
#token_test = 'Token ' + token_contents
token_test = 'token ' + token_contents
#token_test = 'TOK:' + token_contents
#token_test = 'Basic ' + token_contents
#token_test = 'token=' + token_contents
header = {'Authorization' : token_test}
url = 'https://10.10.1.2/api/types/instances'
r = requests.get(url, headers=header, verify=False)
see my commented lines i tried all different types of token settings.
my thoughts were i had to convert the token from bytes to string and remove the double quotes from it , the My_token.content original value property looks like so.
b'"YWRtaW46MTU2OTE4NzkwMgg3NzpjZDdlZWEyNmI2NDJmOTY0ZmI5ZGQ3YzBiNnI2ZTNlZQ"'
Just trying to fig out what i'm misunderstanding with taking the My_token object which works fine and logs me in , but then return the token back on the next request i am trying to perform. thanks
[UPDATE and FIX]
thanks to stovfl's comments i was able to learn more and see my mistakes. i was over thinking this and making it more complex than needed to be ;). I just needed to KISS and just basic auth with my token contents lol.
r_test = requests.get('https://10.10.1.2/api/types/instances', auth=("admin", token_contents), verify=False)

Problems with POST to Quire API

I have been playing with Quire API using python and while the GET calls work fine, I can't do any successful POST calls. I get 400 error: Bad Request. I would appreciate any hints on what I might be doing wrong.
Below are relevant code snippets:
AUTH_ENDPOINT = 'https://quire.io/oauth/token'
API_ENDPOINT = 'https://quire.io/api'
data = {
'grant_type' : 'refresh_token',
'refresh_token' : 'my_refresh_code',
'client_id' : 'my_client_id',
'client_secret' : 'my_client_secret'
}
r = requests.post(url=AUTH_ENDPOINT, data=data)
response = json.loads(r.text)
access_token = response['access_token']
headers = {'Authorization' : 'Bearer {token}'.format(token=access_token)}
# This works fine
r = requests.get(url=API_ENDPOINT + '/user/id/me', headers=headers)
user = json.loads(r.text)
print(user)
# This doesn't work
task_oid = 'my_task_oid'
data = {
'description' : 'Test Comment'
}
r = requests.post(
url=API_ENDPOINT + '/comment/' + task_oid,
data=data,
headers=headers,
)
I am not familiar with the python requests API, so I don't know about default headers.
However it looks like you missed to send the request data as a JSON string:
here what worked for me from java script:
uri: '/comment/my_task_oid',
method: 'POST',
body: '{"description":"hello comment"}'
maybe it helps, in python as well.
also a curl example:
curl -X POST -H 'Authorization: Bearer my_access_token' -d "{\"description\" : \"a test comment\"}" https://quire.io/api/comment/my_task_oid
The answer provided by #cor3000 hinted that post data should be passed as JSON. I tested it out and indeed it works. Here is required modification to the POST reqest:
r = requests.post(
url=API_ENDPOINT + '/comment/' + task_oid,
data=json.dumps(data),
headers=headers,
)
Alternatively you can also do:
r = requests.post(
url=API_ENDPOINT + '/comment/' + task_oid,
json=data,
headers=headers,
)
More details in requests documentation: https://requests.kennethreitz.org/en/master/user/quickstart/#more-complicated-post-requests

"BadRequest" error while using SendMail request of Microsoft Graph API

I am writing a python script to send a mail using the Microsoft Graph API. The mail is sent to only those IDs which exists in our AAD.
I wrote the code:
from adal import AuthenticationContext
import adal
import string
import urllib
import json
import requests
import pprint
import base64
import mimetypes
API_VERSION = 'beta'
RESOURCE = 'https://graph.microsoft.com'
TENANT = <my tenant ID>
CLIENTID = <Client ID>
CLIENTSECRET = <sescret>
DOMAIN = <mydomain>
# AUTHENTICATION - get access token and update session header
def get_session():
authority_host_url = 'https://login.windows.net'
tenant = TENANT
authority_url = authority_host_url + '/' + tenant
service_endpoint = "https://graph.microsoft.com/"
client_id = CLIENTID
client_secret = CLIENTSECRET
# Retrieves authentication tokens from Azure Active Directory and creates a new AuthenticationContext object.
context = AuthenticationContext(authority_url, validate_authority=True, cache=None, api_version=None, timeout=300, enable_pii=False)
# Gets a token for a given resource via client credentials.
token_response = context.acquire_token_with_client_credentials(service_endpoint, client_id, client_secret)
# Create a persistent session with the access token
session = requests.Session()
session.headers.update({'Authorization': f'Bearer {token_response["accessToken"]}', 'SdkVersion': 'python-adal', 'x-client-SKU': 'DynaAdmin'})
#session.headers.update({'Authorization': f'Bearer {token_response["accessToken"]}'})
return session
def build_uri(url):
if 'https' == urllib.parse.urlparse(url).scheme:
return url
result = urllib.parse.urljoin(f'{RESOURCE}/{API_VERSION}/', url.lstrip('/'))
print("\nURL:\n")
print(result)
return result
def sendmail(*, session, subject=None, recipients=None, body='',
content_type='HTML', attachments=None):
"""Helper to send email from current user.
session = user-authenticated session for graph API
subject = email subject (required)
recipients = list of recipient email addresses (required)
body = body of the message
content_type = content type (default is 'HTML')
attachments = list of file attachments (local filenames)
Returns the response from the POST to the sendmail API.
"""
# Verify that required arguments have been passed.
if not all([session, subject, recipients]):
raise ValueError('sendmail(): required arguments missing')
# Create recipient list in required format.
recipient_list = [{'EmailAddress': {'Address': address}}
for address in recipients]
# Create list of attachments in required format.
attached_files = []
if attachments:
for filename in attachments:
b64_content = base64.b64encode(open(filename, 'rb').read())
mime_type = mimetypes.guess_type(filename)[0]
mime_type = mime_type if mime_type else ''
attached_files.append( \
{'#odata.type': '#microsoft.graph.fileAttachment',
'ContentBytes': b64_content.decode('utf-8'),
'ContentType': mime_type,
'Name': filename})
# Create email message in required format.
email_msg = {'Message': {'Subject': subject,
'Body': {'ContentType': content_type, 'Content': body},
'ToRecipients': recipient_list,
'Attachments': attached_files},
'SaveToSentItems': 'true'}
print("\nBody:\n")
print(email_msg)
# Do a POST to Graph's sendMail API and return the response.
resp = session.post(build_uri('/users/8368b7b5-b337ac267220/sendMail'), data=email_msg, stream=True, headers={'Content-Type': 'application/json'})
return resp
# ------------ RUN CODE ------------
session = get_session()
myRecipients = "sea.chen#mydomain.com;anj.dy#mydomain.com"
response = sendmail(session=session,
subject= "hai",
recipients=myRecipients.split(';'),
body="hai this is a new mail")
print("\nRequest headers: \n")
print(response.request.headers)
print("\nResponse: \n")
print(response)
print(response.text)
The output I got is :
Body:
{'Message': {'Subject': 'hai', 'Body': {'ContentType': 'HTML', 'Content': 'hai this is a new mail'}, 'ToRecipients': [{'EmailAddress': {'Address': 'sea.chen#mydomain.com'}}, {'EmailAddress': {'Address': 'anj.dy#mydomain.com'}}], 'Attachments': []}, 'SaveToSentItems': 'true'}
URL:
https://graph.microsoft.com/beta/users/8368b7b5-b337ac267220/sendMail
Request headers:
{'User-Agent': 'python-requests/2.22.0', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Authorization': 'Bearer eyJ0eXAiOiJKV1QiLCJub25jZSI6IkFRQUJBQUFBQUFEQ29NcGpKWHJ4VHE5Vkc5dGUtN0ZYVzRQOWpybFRZWXdIVmZieWJxd0dUVUtNRThqUG5Va0hFSlowU2JyUFRaaDlaSjdURklVMjRwV1RpOTQxZU5kaXpIeHdXdDk0ODNlYmY1OWE5IiwiYXBwaWRhY3IiOiIxIiwiaWRwIjoiaHR0cHM6Ly9zdHMud2luZG93cy5uZXQvOWFmYjFmOGEtMjE5Mi00NWJhLWIwYTEtNmIxOTNjNzU4ZTI0LyIsIm9pZCI6ImI3NDY4ZDQxLTkxMWMtNGU4ZS1iMzA4LWY5NmM1ZGQ4MDVmMyIsInJvbGVzIjpbIlVzZXIuUmVhZFdyaXRlLkFsbCIsIkdyb3VwLlJlYWQuQWxsIiwiRGlyZWN0b3J5LlJlYWRXcml0ZS5BbGwiLCJHcm91cC5SZWFkV3JpdGUuQWxsIiwiRGlyZWN0b3J5LlJlYWQuQWxsIiwiVXNlci5SZWFkLkFsbCIsIk1haWwuU2VuZCJdLCJzdWIiOiJiNzQ2OGQ0MS05MTFjLTRlOGUtYjMwOC1mOTZjNWRkODA1ZjMiLCJ0aWQiOiI5YWZiMWY4YS0yMTkyLTQ1YmEtYjBhMS02YjE5M2M3NThlMjQiLCJ1dGkiOiJWX1d6UHJjUDhrQ000MGNPM0xZZkFBIiwidmVyIjoiMS4wIiwieG1zX3RjZHQiOjE0NTY0Nzc5MzB9.Nq0qdmfd4qAQWdnaFLVNKYWQ__t52jRYC09IsDlrSOoAhZU6d2M6ePAAaKFSR-Ss_NJ4o21FAbxRM8mRUumW3n1TFvARN0FDzjtZMG9mgIrPmYndfRQtcD3s7f5Q5JOQdtd5QDRVhPqVRNAwmC-o_TW5mm0p40oIR2Mc2MN_MB3dp-_0xH7fN3xsPzWi9yRR1-iHnvEjLmhKecY5pxCBO3RW5QVcAR6DH6kw0koV49cmjpIu-_gau4SFlF4kFdwEVXdv1jTeJj91lA02Ar9tR-2hQiPOaqsloSmKpaH0Tb4LwGQJBk2O8fiwy5Sv2NoKbi6QE2EPFck7jZPVBDh35g', 'SdkVersion': 'python-adal', 'x-client-SKU': 'DynaAdmin', 'Content-Type': 'application/json', 'Content-Length': '90'}
Response:
<Response [400]>
{
"error": {
"code": "BadRequest",
"message": "Unable to read JSON request payload. Please ensure Content-Type header is set and payload is of valid JSON format.",
"innerError": {
"request-id": "26ef0c0b-c362-401c-b8ed-48755a45d086",
"date": "2019-06-24T07:10:53"
}
}
}
The error I got is :
Unable to read JSON request payload. Please ensure Content-Type header
is set and payload is of valid JSON format.
So I tried the request in Graph Explorer and used the same URL and body I got printed in the above output. The request sent from Graph Explorer was successful and the mail was sent to the correct recipients. That means the content-body is valid.
It is obvious from the above output that the bearer token, and 'Content-Type': 'application/json' were passed as the header.
Then why I am getting the error while running the script?
Can anyone please help me?
Most likely the body of your POST is not properly formatted. When I did this with the requests library, I found I needed to set data like so:
data = json.dumps(email_msg)
The default for data is to form-encode, not pass as JSON. Have a look at https://learn.microsoft.com/outlook/rest/python-tutorial#contents-of-tutorialoutlookservicepy
Thanks for sharing this.
I had different issue when I was trying to get Graph API to send one-on-one chat message to Microsoft Teams. I could run the following code using http.client and get most of the messages posted in chat.
import http.client
headers = {'Content-type':'application/json',
"Authorization": f"Bearer {getGraphAccessToken()}"
}
body = {
"body": {
"contentType": "text",
"charset" : "utf-8",
"content": text
}}
connection = http.client.HTTPSConnection("graph.microsoft.com")
connection.request("POST",f"/v1.0/chats/{chatId}/messages",headers=headers, body = str(body))
However when I had certain emojis inside the text I got the following error:
"Unable to read JSON request payload. Please ensure Content-Type header is set and payload is of valid JSON format."
By switching the library to requests I was able to send the message with special emojis to work.
import requests
import json
headers = {'Content-type':'application/json',
"Authorization": f"Bearer {getGraphAccessToken()}"
}
body = {
"body": {
"contentType": "text",
"content": text
}}
requests.post(f"https://graph.microsoft.com/v1.0/chats/{chatId}/messages",headers=headers,data =json.dumps(body) )

Converting Python Request library to Nodejs

I am trying to convert the Python request code into Nodejs, however, I cannot find the corresponding usage in Nodsjs. I want to POST request using authentication looks like this
Python code:
resp = requests.post(url, auth=HTTPBasicAuth(username, password), verify=False)
print resp.content
When I use the code in Nodejs:
request.post(url).auth('username', 'password', false);
It is not working. I have no idea how to pass the auth in the post function. Any helps
You can try:
var client = http.createClient(80, 'www.site.tld');
var user = 'user';
var passwd = 'pa$$';
var auth = 'Basic ' + Buffer.from(user + ':' + passwd).toString('base64');
var header = {'Host': 'www.site.tld', 'Authorization': auth};
var request = client.request('POST', '/', header);

Categories