You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java中使用Spotify API时授权码无效问题求助

问题分析与修复方案

核心问题1:授权码的一次性特性

Spotify的授权码(code)是一次性有效的。你先调用同步方法authorizationCode_Sync()完成了授权码交换,后续异步方法authorizationCode_Async()再复用同一个code,就会触发Invalid authorization code错误。

核心问题2:未请求offline_access权限范围

要获取refresh token,必须在生成授权URI时显式添加offline_access scope。你的AuthorizationCodeUriExample代码未设置任何scope,默认不会返回refresh token。


修复步骤

1. 修正授权URI生成代码,添加必要Scope

修改授权请求构建逻辑,加入offline_access及业务所需的其他scope(如user-read-private):

import se.michaelthelin.spotify.SpotifyApi;
import se.michaelthelin.spotify.SpotifyHttpManager;
import se.michaelthelin.spotify.requests.authorization.authorization_code.AuthorizationCodeUriRequest;

import java.net.URI;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;

public class AuthorizationCodeUriExample {
    private static final String clientId = "<client_id>";
    private static final String clientSecret = "<client_secret>";
    private static final URI redirectUri = SpotifyHttpManager.makeUri("https://example.com/spotify-test-uri");

    private static final SpotifyApi spotifyApi = new SpotifyApi.Builder()
            .setClientId(clientId)
            .setClientSecret(clientSecret)
            .setRedirectUri(redirectUri)
            .build();
    private static final AuthorizationCodeUriRequest authorizationCodeUriRequest = spotifyApi.authorizationCodeUri()
            // 添加offline_access以获取refresh token,可追加其他需要的权限
            .scope("offline_access user-read-private")
            .build();

    public static void authorizationCodeUri_Sync() {
        final URI uri = authorizationCodeUriRequest.execute();
        System.out.println("URI: " + uri.toString());
    }

    public static void authorizationCodeUri_Async() {
        try {
            final CompletableFuture<URI> uriFuture = authorizationCodeUriRequest.executeAsync();
            final URI uri = uriFuture.join();
            System.out.println("URI: " + uri.toString());
        } catch (CompletionException e) {
            System.out.println("Error: " + e.getCause().getMessage());
        } catch (CancellationException e) {
            System.out.println("Async operation cancelled.");
        }
    }

    public static void main(String[] args) {
        authorizationCodeUri_Sync();
    }
}

提示:只需调用同步或异步生成URI的其中一种即可,无需重复调用。

2. 修正授权码交换代码,确保授权码仅使用一次

修改代码,每次交换都使用全新的授权码,且只保留同步/异步其中一种调用逻辑:

import se.michaelthelin.spotify.SpotifyApi;
import se.michaelthelin.spotify.SpotifyHttpManager;
import se.michaelthelin.spotify.exceptions.SpotifyWebApiException;
import se.michaelthelin.spotify.model_objects.credentials.AuthorizationCodeCredentials;
import se.michaelthelin.spotify.requests.authorization.authorization_code.AuthorizationCodeRequest;
import org.apache.hc.core5.http.ParseException;

import java.io.IOException;
import java.net.URI;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;

public class AuthorizationCodeExample {
    private static final String clientId = "<client ID>";
    private static final String clientSecret = "<client secret>";
    private static final URI redirectUri = SpotifyHttpManager.makeUri("https://example.com/spotify-test-uri");
    // 每次都替换为新获取的授权码
    private static final String code = "<new_authorization_code>";

    private static final SpotifyApi spotifyApi = new SpotifyApi.Builder()
            .setClientId(clientId)
            .setClientSecret(clientSecret)
            .setRedirectUri(redirectUri)
            .build();
    private static final AuthorizationCodeRequest authorizationCodeRequest = spotifyApi.authorizationCode(code)
            .build();

    public static void authorizationCode_Sync() {
        try {
            final AuthorizationCodeCredentials authorizationCodeCredentials = authorizationCodeRequest.execute();

            spotifyApi.setAccessToken(authorizationCodeCredentials.getAccessToken());
            spotifyApi.setRefreshToken(authorizationCodeCredentials.getRefreshToken());

            System.out.println("Expires in: " + authorizationCodeCredentials.getExpiresIn());
            System.out.println("Refresh Token: " + authorizationCodeCredentials.getRefreshToken());
        } catch (IOException | SpotifyWebApiException | ParseException e) {
            System.out.println("Error: " + e.getMessage());
        }
    }

    public static void main(String[] args) {
        authorizationCode_Sync();
        // 若使用异步,注释同步调用,打开下面的异步调用
        // authorizationCode_Async();
    }
}

额外注意事项

  • 每次授权跳转得到的code仅能使用一次,失效后需重新获取新code。
  • 确保Spotify开发者后台配置的Redirect URI与代码中完全一致,包括协议、域名、路径,大小写敏感。
  • 生产环境中避免用join()阻塞异步线程,推荐使用thenAccept()等异步回调处理结果。

内容的提问来源于stack exchange,提问作者Rickity2207

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 07:52:53