TootLoops
TootLoops

Reputation: 21

How to get access token from Spotify API?

I am fairly new to programming with Java but am interested in creating a program that allows for connection to the Spotify API. I am using the Client Credential Flow authorization process but keep getting java.io.IOException: insufficient data written exception when trying to reach the access token. I cannot figure out what information I am missing to complete the request.

I found a YouTube video of the same process being completed in Python and they utilized the requests feature and .json() to receive the access token. Is there a similar way to complete this in Java?

        try {
    String str = "application/x-www-form-urlencoded";
    byte[]  hold = str.getBytes();
    
    //create url
    URL url = new URL(tokenURL);
    //open connection to url
    conn = (HttpURLConnection) url.openConnection();
    conn.setDoOutput(true); 
    conn.setDoInput(true);
    
    //setup post headers and body
    conn.setRequestMethod("POST");
    conn.setFixedLengthStreamingMode(32);
    conn.setRequestProperty("Authorization",String.format("Basic %s", clientCredEncode));
    conn.setRequestProperty("grant_type", "client_credentials");
    conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
    conn.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.85 Safari/537.36");
    
    //validate connection
    int val = conn.getResponseCode();
    String response = conn.getResponseMessage();
    System.out.println("response code: " + val);
    System.out.println("response: " + response);

    }catch(Exception e){
        System.out.println("error: " + e); 
        conn.disconnect();
    }

PYTHON CODE This code performs the action in python.

def spotifyAuth(clientID, clientSecret):
clientCred = f"{clientID}:{clientSecret}"
encodedClient = base64.b64encode(clientCred.encode())

tokenURL = "https://accounts.spotify.com/api/token"
method = "POST"

tokenData = {"grant_type" : "client_credentials"}

tokenHeader = {"Authorization" : f"Basic {encodedClient.decode()}"}

r = requests.post(tokenURL, data=tokenData, headers=tokenHeader)
tokenResponse = r.json()

accessToken = tokenResponse['access_token']
expires = tokenResponse['expires_in']

return accessToken, expires

Upvotes: 0

Views: 2332

Answers (3)

Antonio Sampere
Antonio Sampere

Reputation: 1

Thank you for your code. I've tried it, just a thing on the Santhosh answer, I've a ClassCastException:

class com.google.gson.JsonPrimitive cannot be cast to class
com.google.gson.JsonObject (com.google.gson.JsonPrimitive and
com.google.gson.JsonObject are in unnamed module of loader 'app')

These calls:

getAsJsonObject().getAsJsonObject("access_token")
getAsJsonObject().getAsJsonObject("expires_in")

work this way:

getAsJsonObject().getAsJsonPrimitive("access_token")
getAsJsonObject().getAsJsonPrimitive("expires_in")

Upvotes: 0

Santhosh
Santhosh

Reputation: 91

For anyone whos looking for the same, Here's a better one

import com.google.gson.JsonParser;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;

public class SpotifyToken {
    public String accessToken = "";
    public String expiresIn = "";


    public void get() throws IOException {

        URL url = new URL(Endpoints.TOKEN);
        HttpURLConnection http = (HttpURLConnection) url.openConnection();
        http.setRequestMethod("POST");
        http.setDoOutput(true);
        http.setRequestProperty("content-type", "application/x-www-form-urlencoded");

        String data = "grant_type=client_credentials&client_id=" + Endpoints.CLIENT_ID + "&client_secret=" + Endpoints.CLIENT_SECRET + "";

        byte[] out = data.getBytes(StandardCharsets.UTF_8);

        OutputStream stream = http.getOutputStream();
        stream.write(out);

        BufferedReader Lines = new BufferedReader(new InputStreamReader(http.getInputStream()));
        String currentLine = Lines.readLine();
        StringBuilder response = new StringBuilder();
        while (currentLine != null) {
            response.append(currentLine).append("\n");
            currentLine = Lines.readLine();
        }

        this.accessToken = String.valueOf(JsonParser.parseString(String.valueOf(response)).getAsJsonObject().getAsJsonObject("access_token"));
        this.expiresIn = String.valueOf(JsonParser.parseString(String.valueOf(response)).getAsJsonObject().getAsJsonObject("expires_in"));

        http.disconnect();
    }
}

The class Endpoints.java will be

public class Endpoints {
    public static final String CLIENT_ID = "YOUR_CLIENT_ID";
    public static final String CLIENT_SECRET = "YOUR_CLIENT_SECRET";
    public static final String TOKEN = "https://accounts.spotify.com/api/token";
}

If it interests you, here is the cURL command for the same:

curl --request POST \
  --url 'https://accounts.spotify.com/api/token' \
  --header 'content-type: application/x-www-form-urlencoded' \
  --data grant_type=client_credentials \
  --data client_id=YOUR_CLIENT_ID \
  --data client_secret=YOUR_CLIENT_SECRET \

I used this tool to convert cURL to java code.

Upvotes: 0

TootLoops
TootLoops

Reputation: 21

Thanks to Rup I was able to identify the issue. I was not properly sending anything with the POST. I added .getOutputStream() so send the request and .getInputStream() to receive the response.

    //create url access point
    URL url = new URL(tokenURL);
    
    //open http connection to url
    conn = (HttpURLConnection) url.openConnection();
    conn.setDoOutput(true); 
    conn.setDoInput(true);
    
    //setup post function and request headers
    conn.setRequestMethod("POST");
    conn.setRequestProperty("Authorization",String.format("Basic %s", clientCredEncode));
    conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");

    //set body for posting
    String body = "grant_type=client_credentials";
    
    //calculate and set content length
    byte[] out = body.getBytes(StandardCharsets.UTF_8);
    int length = out.length; 
    conn.setFixedLengthStreamingMode(length);
    
    //connect to http
    conn.connect();
    //}
    
    //send bytes to spotify
    try(OutputStream os = conn.getOutputStream()) {
        os.write(out);
    }
    
    //receive access token
    InputStream result = conn.getInputStream();
    s = new String(result.readAllBytes());
    //System.out.println(s);

Upvotes: 2

Related Questions