I'm trying to get the Spotify credentials API to work in Clojure and am having some difficulties. Have currently implemented the following (creds removed for obvious reasons) to mimic the JS version on the linked page, but keep getting status 400 responses. If anyone can help me out, that would be awesome!
(ns api-test.spotify
(:require [clj-http.client :as client])
(:require [clojure.string :as string])
(:import java.util.Base64))
(def app-creds
{:id "id creds here"
:secret "secret creds here"})
(def token-url "https://accounts.spotify.com/api/token")
(defn encode [to-encode]
(.encodeToString (Base64/getEncoder) (.getBytes to-encode)))
(defn app-creds->encoded
[app-creds]
(encode (str (:id app-creds) ":" (:secret app-creds))))
(defn get-token
[app-creds]
(client/post token-url {:basic-auth (app-creds->encoded app-creds)}))
CodePudding user response:
You can use clj-spotify:
Dependency: [clj-spotify "0.1.10"]
(clj-spotify.util/get-access-token id-here secret-here)
If you are interested in the implementation, see source:
(ns clj-spotify.util
(:require [clj-http.client :as client]
[clojure.data.codec.base64 :as b64]
[clojure.java.io :as io])
(:import [org.apache.commons.io IOUtils]))
(defn get-access-token
"Requests an access token from Spotify's API via the Client Credentials flow.
The returned token cannot be used for endpoints which access private user information;
use the OAuth 2 Authorization Code flow for that."
[client-id client-secret]
(-> "https://accounts.spotify.com/api/token"
(client/post {:form-params {:grant_type "client_credentials"}
:basic-auth [client-id client-secret]
:as :json})
:body
:access_token))
CodePudding user response:
According to the docs you shared, you are missing the required "grant_type" parameter in the request body.
Moreover, The content-type header is also required to be set to "x-www-form-url-encoded" but this is something that works out of the box with clj-http.
Finally, You also don't have to construct Authorization header manually because clj-http supports that.
Here's the code that worked for me:
(defn get-token [{:keys [id secret] :as creds}]
(:body (http/post "https://accounts.spotify.com/api/token"
{#_#_:content-type :x-www-form-urlencoded
:as :json
:basic-auth [id secret]
:form-params {"grant_type" "client_credentials"}})))
(comment
(get-token {:id "xxx"
:secret "yyy"})
;; => {:access_token
;; "BQB...",
;; :token_type "Bearer",
;; :expires_in 3600}
)
In all cases, read the server error response body - I got a nice error message when I didn't pass "grant_type" parameter properly:
"{\"error\":\"unsupported_grant_type\",\"error_description\":\"grant_type parameter is missing\"}",