Why do I get the error unsupported_grant_type when trying to make a POST request to Spotify API when trying to get a token?

Viewed 44

Trying to fetch a token from the Spotify API using reqwest. Keep getting this error from the response:

{"error":"unsupported_grant_type","error_description":"grant_type parameter is missing"}

Tried multiple solutions: adding grant_type as parameters, stringifying

use std::collections::HashMap;

use reqwest::header;
use reqwest::header::HeaderValue;
use reqwest::{Body, Client};

use crate::header::{AUTHORIZATION, CONTENT_LENGTH, CONTENT_TYPE};

const CLIENT_ID: &str = "<CLIENT_ID>";
const CLIENT_SECRET: &str = "<CLIENT_SECRET>";

async fn get_token() -> Result<String, Box<dyn std::error::Error>> {
    let mut encoded = CLIENT_ID.to_string();
    encoded.push_str(":");
    encoded.push_str(&CLIENT_SECRET);
    encoded = base64::encode(encoded);

    let mut header_construct = "Basic ".to_string();
    header_construct.push_str(&encoded);

    let header_value = header_construct.as_str();

    println!("{}", header_value);

    let mut headers = header::HeaderMap::new();
    headers.insert(AUTHORIZATION, header_value.parse().unwrap());
    headers.insert(CONTENT_LENGTH, HeaderValue::from(0));
    headers.insert(
        CONTENT_TYPE,
        HeaderValue::from_static("application/x-www-form-urlencoded"),
    );

    let grant_string = "grant_type=client_credentials".to_string();
    println!("{}", grant_string);

    let mut params = HashMap::new();
    params.insert("grant_type", "client_credentials");

    let client = Client::new();
    let body = client
        .post("https://accounts.spotify.com/api/token")
        .body(Body::from(grant_string))
        .headers(headers)
        .send()
        .await?
        .text()
        .await?;
    Ok(body)
}

#[tokio::main]
async fn main() {
    let fact = get_token().await;
    println!("fact = {:#?}", fact);
}
1 Answers

The issue is here:

headers.insert(CONTENT_LENGTH, HeaderValue::from(0));

This is setting the header Content-Length: 0 on the post request, which indicates that the request has no body content. However, we do want it to have body content, namely the form-encoded grant_type parameter. To fix this, don't set the Content-Length header at all, as reqwest will do it for us automatically based on the body. Additionally, using .form() to add the request parameters will cause reqwest to add Content-Type: application/x-www-form-urlencoded automatically. With this in mind, here's a simplified get_token():

async fn get_token() -> Result<String, Box<dyn std::error::Error>> {
    let auth = format!("Basic {}", base64::encode(format!("{}:{}", CLIENT_ID, CLIENT_SECRET)));
    let params = [("grant_type", "client_credentials")];

    let client = reqwest::Client::new();
    let body = client
        .post("https://accounts.spotify.com/api/token")
        .header("Authorization", &auth)
        .form(&params)
        .send()
        .await?
        .text()
        .await?;
    Ok(body)
}
Related