I’m working on a Spring Boot app that needs to connect with Spotify’s web API. The user has to log into their Spotify account first through OAuth2.
I can get users to the login screen fine, but once they approve access, I’m hitting a 403 error saying I don’t have permission to view the page. My app has a homepage with a “Connect to Spotify” button that takes them to auth, then should redirect to another page after success. Instead I get the authorization error.
I think the issue is in my handleSpotifyCallback method. After the user approves on Spotify’s page, the redirect fails with unauthorized error. Maybe my token handling is wrong and the access token isn’t being set properly. Here’s my authentication controller:
import java.io.IOException;
import java.net.URI;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import jakarta.servlet.http.HttpServletResponse;
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 se.michaelthelin.spotify.requests.authorization.authorization_code.AuthorizationCodeUriRequest;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.view.RedirectView;
@RestController
@RequestMapping("/auth")
public class SpotifyAuthController {
private static final URI callbackUri = SpotifyHttpManager.makeUri("http://localhost:8080/auth/callback/");
private String authCode = "";
private String userRefreshToken = "";
private static final SpotifyApi spotifyClient = new SpotifyApi.Builder()
.setClientId("13e244917ca64efb96556f753fcd032b")
.setClientSecret("ded93049447347769bcea9b2327c7ba6")
.setRedirectUri(callbackUri)
.build();
@GetMapping("authorize")
@ResponseBody
public RedirectView initiateSpotifyAuth() {
AuthorizationCodeUriRequest authUriRequest = spotifyClient.authorizationCodeUri()
.scope("playlist-modify-public, user-read-private, user-read-email, user-top-read")
.show_dialog(true)
.build();
final URI authUri = authUriRequest.execute();
RedirectView redirect = new RedirectView();
redirect.setUrl(authUri.toString());
return redirect;
}
@GetMapping(value = "callback")
public String handleSpotifyCallback(@RequestParam("code") String authorizationCode, HttpServletResponse response) throws IOException {
System.out.println("Got authorization code: " + authorizationCode);
if (authorizationCode == null || authorizationCode.isEmpty()) {
return "Missing authorization code in callback.";
}
AuthorizationCodeRequest tokenRequest = spotifyClient.authorizationCode(authorizationCode).build();
try {
final AuthorizationCodeCredentials tokenCredentials = tokenRequest.execute();
spotifyClient.setAccessToken(tokenCredentials.getAccessToken());
spotifyClient.setRefreshToken(tokenCredentials.getRefreshToken());
userRefreshToken = tokenCredentials.getRefreshToken();
System.out.println("Got Access Token: " + tokenCredentials.getAccessToken());
System.out.println("Got Refresh Token: " + tokenCredentials.getRefreshToken());
System.out.println("Token expires in: " + tokenCredentials.getExpiresIn());
} catch (IOException | SpotifyWebApiException | org.apache.hc.core5.http.ParseException ex) {
System.out.println("Token exchange failed: " + ex.getMessage());
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Token exchange failed.");
return "Token exchange failed.";
}
response.sendRedirect("http://localhost:8080/dashboard");
return spotifyClient.getAccessToken();
}
}