I’m working on a Flask application that connects to Spotify’s Web API using the authorization code flow. My current implementation works fine, but I’m running into an issue with how I handle the authentication process.
import os
import requests
import urllib.parse
from flask import Flask, request, session, redirect, url_for, jsonify
import base64
app = Flask(__name__)
app.secret_key = 'my_secret_key'
SPOTIFY_AUTH_URL = 'https://accounts.spotify.com/authorize'
SPOTIFY_TOKEN_URL = 'https://accounts.spotify.com/api/token'
SPOTIFY_API_URL = 'https://api.spotify.com/v1'
APP_ID = "your_client_id"
APP_SECRET = "your_client_secret"
CALLBACK_URL = "http://localhost:5000/auth_callback"
permissions = 'user-read-private user-read-email'
@app.route('/')
def index():
return "Welcome <a href='/authenticate'>Connect Spotify</a>"
@app.route('/authenticate', methods=['GET'])
def authenticate():
permissions = 'playlist-read-private user-library-read'
query_params = {
'client_id': APP_ID,
'response_type': 'code',
'redirect_uri': CALLBACK_URL,
'scope': permissions,
'show_dialog': True
}
spotify_auth_url = f"{SPOTIFY_AUTH_URL}?{urllib.parse.urlencode(query_params)}"
return redirect(spotify_auth_url)
@app.route('/auth_callback', methods=['GET'])
def auth_callback():
if 'error' in request.args:
return jsonify({'error': request.args['error']})
auth_code = request.args.get('code')
if not auth_code:
return jsonify({'error': 'Authorization code missing'})
credentials = base64.b64encode(
f"{APP_ID}:{APP_SECRET}".encode()
).decode()
request_headers = {
'Authorization': f'Basic {credentials}',
'Content-Type': 'application/x-www-form-urlencoded'
}
token_data = {
'grant_type': 'authorization_code',
'code': auth_code,
'redirect_uri': CALLBACK_URL
}
try:
token_response = requests.post(SPOTIFY_TOKEN_URL, headers=request_headers, data=token_data)
token_response.raise_for_status()
return jsonify(token_response.json())
except requests.exceptions.RequestException as error:
return jsonify({
'error': 'Token exchange failed',
'message': str(error)
}), 500
if __name__ == '__main__':
app.run(port=5000, debug=True)
The problem I’m facing is that while this approach works correctly, I want to avoid redirecting users to the Spotify authorization URL with all those query parameters. Instead, I’d prefer to make a direct GET request and handle the response in my callback function. When I try this approach, I can retrieve the authorization code from the arguments, but I’m getting authentication errors when trying to exchange it for an access token via POST request. Is this behavior intentional on Spotify’s part to prevent certain types of requests, or am I missing something in my implementation? I’m specifically using the authorization code grant type for this integration.