Spotify API授权码流(Authorization Code Flow)实现失败:invalid_grant错误及授权跳转异常问题排查
Let's break down what's going wrong here and fix your Spotify authorization code flow step by step—this is a common gotcha for beginners, so don't worry!
1. Why You're Not Seeing the Authorization Page or Redirect
You're passing critical authorization parameters (client_id, response_type, etc.) in the request headers, but Spotify's authorization endpoint requires these values to be sent as URL query parameters instead. The server isn't recognizing your request as a valid authorization prompt, so it returns a generic 200 response instead of redirecting to the login/permission screen.
2. Why Your Authorization Code is Invalid
You're trying to use the full requests.get response object as your authorization code, which is completely incorrect. The actual authorization code is a string that Spotify sends to your specified redirect_uri after the user logs in and approves permissions—it will appear as a query parameter in the URL of the page you're redirected to (e.g., https://your-redirect-uri.com?code=VALID_AUTH_CODE_HERE).
Corrected Code & Step-by-Step Walkthrough
Here's a revised version of your class with proper authorization flow handling, plus instructions on how to use it:
import requests import base64 import datetime class SpotifyAPIFlow(object): access_token = None access_token_expires = datetime.datetime.now() access_token_did_expire = True client_id = None client_secret = None token_url = "https://accounts.spotify.com/api/token" auth_url = "https://accounts.spotify.com/authorize" def __init__(self, client_id, client_secret, *args, **kwargs): super().__init__(*args, **kwargs) self.client_id = client_id self.client_secret = client_secret def get_client_credentials(self): """Return a base64 encoded client ID/secret string""" if self.client_secret is None or self.client_id is None: raise Exception("You must set client ID and client secret first!\n") client_creds = f"{self.client_id}:{self.client_secret}" client_creds_b64 = base64.b64encode(client_creds.encode()) return client_creds_b64.decode() def get_token_headers(self): client_creds_b64 = self.get_client_credentials() return {"Authorization": f"Basic {client_creds_b64}"} def generate_auth_url(self): """Build a valid authorization URL to send the user to""" auth_params = { 'client_id': self.client_id, 'response_type': 'code', 'redirect_uri': 'https://open.spotify.com/collection/playlists', # Must match your Spotify Dashboard setting! 'scope': 'user-top-read' } # Automatically format parameters into a valid URL return requests.Request('GET', self.auth_url, params=auth_params).prepare().url def exchange_code_for_token(self, auth_code): """Exchange a valid authorization code for an access token""" token_headers = self.get_token_headers() payload = { 'grant_type': 'authorization_code', 'code': auth_code, 'redirect_uri': 'https://open.spotify.com/collection/playlists', # Exact match to the auth URL's redirect URI } access_token_request = requests.post(url=self.token_url, data=payload, headers=token_headers) if access_token_request.status_code == 200: response_data = access_token_request.json() self.access_token = response_data['access_token'] expires_in = response_data['expires_in'] self.access_token_expires = datetime.datetime.now() + datetime.timedelta(seconds=expires_in) self.access_token_did_expire = self.access_token_expires < datetime.datetime.now() return response_data else: print(f"Token exchange failed: {access_token_request.json()}") return None
How to Use This Code:
- Step 1: Initialize the class with your Spotify client ID and secret (from the Spotify Developer Dashboard):
spotify_auth = SpotifyAPIFlow("your_client_id", "your_client_secret") - Step 2: Generate the authorization URL and open it in your browser:
auth_url = spotify_auth.generate_auth_url() print("Open this URL in your browser to authorize:", auth_url) - Step 3: After logging in and approving permissions, Spotify will redirect you to your
redirect_uri. Copy thecodeparameter from the end of the URL (e.g., the string after?code=). - Step 4: Exchange the code for an access token:
user_auth_code = input("Paste the authorization code here: ") token_data = spotify_auth.exchange_code_for_token(user_auth_code) print("Success! Token data:", token_data)
Critical Reminders:
- Redirect URI Must Match: The
redirect_uriin your code must be exactly the same as the one you added to your app in the Spotify Developer Dashboard (including capitalization and trailing slashes). Mismatches will cause errors. - Authorization Codes Are Single-Use: Each code can only be exchanged once—if you get an
invalid_granterror, generate a new authorization URL and get a fresh code. - User Interaction is Required: The authorization code flow is designed to require user consent, so you can't fully automate this process without setting up a local server to capture the redirect (an advanced step for later).
内容的提问来源于stack exchange,提问作者Calin

