Spotify Error 401 even though I, supposedly, have access_token (Python) - python

import requests
import base64
# Request an access token
def request_access_token():
AUTH_URL = 'https://accounts.spotify.com/api/token'
# POST
auth_response = requests.post(AUTH_URL, {
'grant_type': 'client_credentials',
'client_id': "<client ID>",
'client_secret': "<client Secret>",
})
# convert the response to JSON
auth_response_data = auth_response.json()
# save the access token
print(auth_response_data)
access_token = auth_response_data['access_token']
return access_token
# Check if the access token is valid
def check_access_token_validity(access_token):
headers = {
"Authorization": f"Bearer {access_token}"
}
response = requests.get("https://api.spotify.com/v1/me", headers=headers)
print(response)
if response.status_code == 200:
return True
else:
return False
# Run the code
access_token = request_access_token()
if access_token:
if check_access_token_validity(access_token):
print("Access token is valid.")
else:
print("Access token is not valid.")
else:
print("Could not request access token.")
I get a "access_token" but it doesn't work. It gives Error 401. I also got the same issue in javascript. I tried everything and I dont know what is wrong. Here's the output:
output
Which shows that I did recieve a token. But when I try to check it's validity, it is [Invalid 401]. I have also rotated my client secret and same issue. Both Client ID and Client Secret are correct.

As mentioned in the docs, your access token request is different
Try this
import requests
import base64
client_id = 'CLIENT_ID';
client_secret = 'CLIENT_SECRET';
response = requests.post(
'https://accounts.spotify.com/api/token',
data={'grant_type':'client_credentials'},
headers={'Authorization': 'Basic ' + base64.urlsafe_b64encode((CLIENT_ID + ':' + CLIENT_SECRET).encode())},
)

Related

Python Forbidden API Request

I'm trying to use Python 3.10 to retrieve data from an API endpoint using OAUTH2. The authorization call is working correctly and I am receiving the token. However, when I try to retrieve the data I need, I'm getting a 403 message that states
{"code":-1,
"message":"Forbidden Request",
"allowedScopes":{"oauthSystem":{"scopes":["read"]},"oauthCode":{"scopes":["read"]}},
"requestScopes":[]}
My call works in Postman. I've added the scope to the call, but still receive the same message. What am I missing from the call? Here's my code:
# import client libraries
import json
import mysql.connector
import requests
import sys
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
# create database connection
con = mysql.connector.connect(
host='servername',
user='username',
password='password',
database='db_name',
auth_plugin='mysql_native_password')
cursor = con.cursor()
# authentication stuff
def get_new_token():
auth_server_url = "https://URL_here"
client_id = "the client ID"
client_secret = "the client secret"
token_req_payload = {'grant_type': 'client_credentials'}
token_response = requests.post(auth_server_url,
data=token_req_payload, verify=False, allow_redirects=False,
auth=(client_id, client_secret))
if token_response.status_code !=200:
print("Failed to get token", file=sys.stderr)
sys.exit(1)
else:
print("Obtained Token")
tokens = json.loads(token_response.text)
return tokens['access_token']
# use the function above to get the token before calling the API
token = get_new_token()
print("The token is ", token)
# call the API using the token
api_headers = {'Authorization': 'Bearer ' + token, 'Host_name)': 'host','Scope': 'read', 'User-Agent': 'PostmanRuntime/7/30.0', 'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate, br',
'Connection': 'keep-alive'}
api_response = requests.get('https://api_endpoint_url', headers=api_headers, verify=False)
if api_response.status_code == 401:
print("Failed to get token.")
token = get_new_token()
else:
print(api_response.text)
print(api_response.status_code)
I've tried adding the scope to the headers, but it still returns the same forbidden status. I tried Googling the error message with no results. The MySQL connection stuff is for additional functionality I will add later.
I solved this by adding the scope to the authentication request instead of the data request, so now the authentication request is:
def get_new_token():
auth_server_url = "https://URL_here"
client_id = "the client ID"
client_secret = "the client secret"
token_req_payload = {'grant_type': 'client_credentials', 'scope': 'read'}
token_response = requests.post(auth_server_url,
data=token_req_payload, verify=False, allow_redirects=False,
auth=(client_id, client_secret))
if token_response.status_code !=200:
print("Failed to get token", file=sys.stderr)
sys.exit(1)
else:
print("Obtained Token")
tokens = json.loads(token_response.text)
return tokens['access_token']
# use the function above to get the token before calling the API
token = get_new_token()
print("The token is ", token)

Spotify API, getting 404 as a response trying to find current song

Am trying to make a program that finds the current song playing and then to put it an one of my playlists. But am getting a 404 response when a trying to obtain the current playing song.
This is how I am getting my access token:
def get_token():
auth_str = client_id + ":" + client_secret
auth_bytes = auth_str.encode("utf-8")
auth_base64 = str(base64.b64encode(auth_bytes), "utf-8")
url = "https://accounts.spotify.com/api/token"
headers = {
"Authorization": "Basic " + auth_base64,
"Content-Type": "application/x-www-form-urlencoded"
}
data = {"grant_type": "client_credentials"}
result = post(url, headers=headers, data=data)
json_result = json.loads(result.content)
token = json_result["access_token"]
return token
This is how I am creating the headers:
def get_headers(token):
return {"Authorization": "Bearer " + token}
This is how I am trying to get the current playing song uri:
def get_current_track_and_post_in_playlist(token):
headers = get_headers(token)
result = get('https://api.spotify.com/v1/me/player/currently-playing', headers=headers)
playlist_id = "0p4d0akcszc87kcf0pym6qws1"
print(result)
json_result = json.loads(result.content)["item"]["uri"]
print(json_result)
playlist_put = post(f'https://api.spotify.com/v1/playlists/{playlist_id}/tracks?uris={json_result}', headers=headers)
When am printing the result in get_current_track_and_post_in_playlist function i get a <Response [404]>. Can someone help me resolve this problem?
A reasons is required a user authentication for those two REST APIs.
Get Currently Playing Track
https://api.spotify.com/v1/me/player/currently-playing
Add Items to Playlist
https://api.spotify.com/v1/playlists/{playlist_id}/tracks
It needs to get token by Authorization Code Flow
So I will demo by local server with Flask
This overall steps
# Step 1
I play a song by browser. it will add into my playlist
# Step 2
Running local redirect server with this code with add-song.py file name.
You needs to config the Redirect URIs of your application in your dashboard.
https://developer.spotify.com/dashboard/applications
from flask import Flask, request, redirect
from requests_oauthlib import OAuth2Session
from requests.auth import HTTPBasicAuth
import requests
import json
app = Flask(__name__)
AUTH_URL = 'https://accounts.spotify.com/authorize'
TOKEN_URL = 'https://accounts.spotify.com/api/token'
REDIRECT_URI = 'http://localhost:3000/callback' # your redirect URI
CLIENT_ID = "<your client ID>"
CLIENT_SECRET = "<your client Secret>"
SCOPE = [
"user-read-playback-state",
"app-remote-control",
"user-modify-playback-state",
"playlist-read-private",
"playlist-read-collaborative",
"user-read-currently-playing",
"user-read-playback-position",
"user-library-modify",
"playlist-modify-private",
"playlist-modify-public",
"user-read-recently-played",
"user-read-private",
"user-library-read"
]
def get_headers(token):
return {"Authorization": "Bearer " + token}
#app.route("/login")
def login():
spotify = OAuth2Session(CLIENT_ID, scope=SCOPE, redirect_uri=REDIRECT_URI)
authorization_url, state = spotify.authorization_url(AUTH_URL)
return redirect(authorization_url)
# your redirect URI's path
#app.route("/callback", methods=['GET'])
def callback():
code = request.args.get('code')
res = requests.post(TOKEN_URL,
auth=HTTPBasicAuth(CLIENT_ID, CLIENT_SECRET),
data={
'grant_type': 'authorization_code',
'code': code,
'redirect_uri': REDIRECT_URI
})
access_token = res.json()['access_token']
listObj = []
listObj.append(res.json())
# get current playing
headers = get_headers(access_token)
result1 = requests.get(url='https://api.spotify.com/v1/me/player/currently-playing', headers=headers)
current_song = result1.json()
listObj.append(current_song)
# Add new song into playlist with current playing song
playlist="<your playlist ID>"
url = "https://api.spotify.com/v1/playlists/{0}/tracks".format(playlist)
# current_song['item']['uri'] = 'spotify:track:xxxxxxxxxxxxxxxx'
params = {'uris': current_song['item']['uri']}
result2 = requests.post(url,
params=params,
headers={'Content-Type':'application/json',
'Authorization': 'Bearer {0}'.format(access_token)})
added_song = result2.json()
listObj.append(added_song)
return listObj
if __name__ == '__main__':
app.run(port=3000,debug=True) # your redirect URI's port
$ python add-song.py
#3 Login by Browser
http://localhost:3000/login
login your Spotify credential
Before add Song
After added Song
In the browser, will display current play song information and added song's snapshot_id.
The key is playing song's track URI needs to set a parameter of add playlist.
current_song['item']['uri']
#Step 4~6
It is running by inside code.
I hope to this demo your are looking for solution.

Python API KeyError

I'm new to both python and APIs. lol. But google isn't helping. I have the below simple authentication request and am getting a KeyError: 'token' from the line, authorization = {"Authorization": "Bearer " + token['token']}
I appreciate any guidance you can provide!
#!/usr/bin/python3
import requests
import argparse
import math
import os
import json
export_format_map = {
"csv": "zip",
"json": "json",
"kml": "kml"
}
def download_logs(args):
"""
NOTE: Requires user credentials
Downloads log files from user-specified host in user-specified file format.
"""
rest_api = "https://address.here/api/1.0"
# Step 1. Login and get token to authenticate requests
print(f"Logging into {rest_api}...")
# Get username and password from environment variables
username = os.environ.get('USERNAME')
password = os.environ.get('PASSWORD')
# Put the credentials into a dictionary object
credentials = {"email": username, "password": password}
r = requests.post(f"{rest_api}/authentication/login", json=credentials)
# Build the JWT compliant authorization dictionary
token = json.loads(r.text)
authorization = {"Authorization": "Bearer " + token['token']}
# Step 2. Gather a list of contacts filtered to be within the min/max timestamps
def get_agents(params):
"""Sends GET request to API with provided parameters; Returns response."""
response = requests.get(
url=f"{rest_api}/agent",
params=params,
headers=authorization
).json()
return response
#code continues.....
I have also tried setting up the token request like this with the same error:
TOKEN = requests.post(
url=f"{rest_api}/authentication/login",
data={
"email": input("\nusername/email: "),
"password": getpass.getpass(),
}
).json()
authorization = {"Authorization": "Bearer " + TOKEN['token']}

Spotify API Authorization Code Flow with Python

I am trying to do the authorization code flow using Spotify's API to ultimately add songs to a playlist. I am building this from scratch, and not using any libraries such as Spotipy.
I am able to successfully hit the authorize endpoint, but I am having some issues with the token endpoint. Here is the code I have so far:
# URLS
AUTH_URL = 'https://accounts.spotify.com/authorize'
TOKEN_URL = 'https://accounts.spotify.com/api/token'
BASE_URL = 'https://api.spotify.com/v1/'
# Make a request to the /authorize endpoint to get an authorization code
auth_code = requests.get(AUTH_URL, {
'client_id': CLIENT_ID,
'response_type': 'code',
'redirect_uri': 'https://open.spotify.com/collection/playlists',
'scope': 'playlist-modify-private',
})
print(auth_code)
auth_header = base64.urlsafe_b64encode((CLIENT_ID + ':' + CLIENT_SECRET).encode('ascii'))
headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic %s' % auth_header.decode('ascii')
}
payload = {
'grant_type': 'authorization_code',
'code': auth_code,
'redirect_uri': 'https://open.spotify.com/collection/playlists',
#'client_id': CLIENT_ID,
#'client_secret': CLIENT_SECRET,
}
# Make a request to the /token endpoint to get an access token
access_token_request = requests.post(url=TOKEN_URL, data=payload, headers=headers)
# convert the response to JSON
access_token_response_data = access_token_request.json()
print(access_token_response_data)
# save the access token
access_token = access_token_response_data['access_token']
When I run my script, I get this output in Terminal:
{'error': 'invalid_grant', 'error_description': 'Invalid authorization code'}
Traceback (most recent call last):
File "auth.py", line 48, in <module>
access_token = access_token_response_data['access_token']
KeyError: 'access_token'```
Can anyone explain to me what I might be doing wrong here?
By now, you probably have figure out what the problem was, but I am answering for future readers as well.
When you encode the auth_header, you should encode it to bytes not ascii. The str.encode() does this by default, so you can call it without arguments. Your code changes to this:
auth_header = base64.urlsafe_b64encode((CLIENT_ID + ':' + CLIENT_SECRET).encode()).
Now you must have a working example.
The code below worked for me to create a playlist and add a song.
The prerequisite is that you have a client_id and client_secret.
Run the code below and browse to your base URL (in my case, that was localhost), then you will see an authorize hyperlink that forwards you to the spotify authorization page.
Note that the redirect_url needs to be whitelisted in the spotify developer dashboard.
from fastapi import FastAPI
from fastapi.responses import HTMLResponse
import requests
import uvicorn
# client_id = "YOUR_CLIENT_ID"
# client_secret = "YOUR_CLIENT_SECRET"
# redirect_uri = "YOUR_REDIRECT_URI" # e.g. http://localhost:8000/callback/ --> you will have to whitelist this url in the spotify developer dashboard
app = FastAPI()
def get_access_token(auth_code: str):
response = requests.post(
"https://accounts.spotify.com/api/token",
data={
"grant_type": "authorization_code",
"code": auth_code,
"redirect_uri": redirect_uri,
},
auth=(client_id, client_secret),
)
access_token = response.json()["access_token"]
return {"Authorization": "Bearer " + access_token}
#app.get("/")
async def auth():
scope = ["playlist-modify-private", "playlist-modify-public"]
auth_url = f"https://accounts.spotify.com/authorize?response_type=code&client_id={client_id}&redirect_uri={redirect_uri}&scope={' '.join(scope)}"
return HTMLResponse(content=f'Authorize')
#app.get("/callback")
async def callback(code):
headers = get_access_token(code)
response = requests.get("https://api.spotify.com/v1/me", headers=headers)
user_id = response.json()["id"]
name = "Name of your playlist"
description = "Description of your playlist"
params = {
"name": name,
"description": description,
"public": True,
}
url = f"https://api.spotify.com/v1/users/{user_id}/playlists"
response = requests.post(url=url, headers=headers, json=params)
playlist_id = response.json()["id"]
track_uri = "spotify:track:319eU2WvplIHzjvogpnNc6"
response = requests.post(
f"https://api.spotify.com/v1/playlists/{playlist_id}/tracks",
headers=headers,
json={"uris": [track_uri]},
)
if response.status_code == 201:
return {"message": "Track added successfully!"}
else:
return {"error": response.json()}
if __name__ == "__main__":
uvicorn.run(app, debug=True)
You're missing the CLIENT_ID and CLIENT_SECRET set within the code if I'm not mistaken.
This means Spotify will return invalid access token, which results in you not being able to continue.
You can also use Spotipy library for Python to make things easier.
https://spotipy.readthedocs.io/en/2.16.1/

Got invalid client secret, missing parameters client_secret, client_assertion when trying to get token in MS Azure

My goal is to get token then querying graph resources.
I wrote these codes to get token from my app. First code, acquire token with login/pass:
from adal import AuthenticationContext
auth_context = AuthenticationContext('https://login.microsoftonline.com/g***************r.onmicrosoft.com')
token = auth_context.acquire_token_with_username_password('https://graph.microsoft.com',
't***************n.fr',
'***************', 'de8bc8b5-***************-b748da725064')
and got these :
adal.adal_error.AdalError: Get Token request returned http error: 401 and server response: {"error":"invalid_client","error_description":"AADSTS7000218: The request body must contain the following parameter: 'client_assertion' or 'client_secret'.\r\nTrace ID: e9ffa752-a258-4e32-9164-156e50912a00\r\nCorrelation ID: afb3c52f-8f36-4904-9926-90ba2aaba0ab\r\nTimestamp: 2020-12-08 14:02:58Z","error_codes":[7000218],"timestamp":"2020-12-08 14:02:58Z","trace_id":"e9ffa752-a258-4e32-9164-156e50912a00","correlation_id":"afb3c52f-8f36-4904-9926-90ba2aaba0ab","error_uri":"https://login.microsoftonline.com/error?code=7000218"}
Second code, acquire token with client credentials:
from adal import AuthenticationContext
auth_context = AuthenticationContext('https://login.microsoftonline.com/g*************r.onmicrosoft.com')
token = auth_context.acquire_token_with_client_credentials('https://graph.microsoft.com',
'de8bc8b5-************-b748da725064',
'****************************')
And got these:
adal.adal_error.AdalError: Get Token request returned http error: 401 and server response: {"error":"invalid_client","error_description":"AADSTS7000215: Invalid client secret is provided.\r\nTrace ID: 79fe51c5-2987-4855-acf5-88fee0592a00\r\nCorrelation ID: cdfc9215-b7a6-4ceb-9d90-2de371c3178c\r\nTimestamp: 2020-12-08 14:21:13Z","error_codes":[7000215],"timestamp":"2020-12-08 14:21:13Z","trace_id":"79fe51c5-2987-4855-acf5-88fee0592a00","correlation_id":"cdfc9215-b7a6-4ceb-9d90-2de371c3178c","error_uri":"https://login.microsoftonline.com/error?code=7000215"}
I don't know if the client secret is wrong or something I did?
I didn't need those libs.
Lib requests was enough.
def authenticate_oauth():
validation_url = 'https://login.microsoftonline.com/******************.com/oauth2/v2.0/token'
client_id = '1a******************************b7'
client_secret = '-*****************************r'
grant_type = 'client_credentials'
scope = 'https://graph.microsoft.com/.default'
params = {
'client_id': client_id,
'client_secret': client_secret,
'grant_type': grant_type,
'scope': scope,
}
response = requests.post(validation_url, data=params)
return json.loads(response.content)
if __name__ == '__main__':
token = authenticate_oauth()
if 'access_token' in token:
graph_data = requests.get(
'https://graph.microsoft.com/v1.0/users',
headers={'Authorization': 'Bearer ' + token['access_token']})
data_users = json.loads(graph_data.content)
for data in data_users['value']:
print(data)

Categories