I am trying to fetch a Spotify API access token. As per these instructions from the Spotify API site:
The request will include parameters in the request body:
- grant_type - Set to “client_credentials”.
The header of this POST request must contain the following parameter:
- Authorization - A Base 64 encoded string that contains the client ID and client secret key. The field must have the format:
Authorization: Basic <base64 encoded client_id:client_secret>
This is usually done by making a POST request to accounts.spotify.com like so:
curl -X "POST" -H "Authorization: Basic ZjM4ZjAw...WY0MzE=" -d grant_type=client_credentials https://accounts.spotify.com/api/token
Yielding:{
"access_token": "NgCXRKc...MzYjw",
"token_type": "bearer",
"expires_in": 3600,
}
I am trying to implement this in Racket like so:
http.rkt
#lang racket
(require net/http-client net/uri-codec)
(define (post hc endpoint data headers)
(define data-encoded (alist->form-urlencoded data))
(http-conn-send!
hc endpoint
#:method "POST"
#:data data-encoded
#:headers
(list
"Content-Type: application/x-www-form-urlencoded"
(format "Content-Length: ~a" (string-length data-encoded))
headers)))
(provide (all-defined-out))
client.rkt
#lang racket
(require
net/base64 net/http-client net/url-connect
racket/bytes racket/port
"http.rkt")
(struct spotify-client (id secret))
(define (hc) (http-conn-open "accounts.spotify.com" #:ssl? #t))
(define (gen-access-token hc client)
(let* ([credentials (string-append (spotify-client-id client) ":" (spotify-client-secret client))]
[enc (bytes->string/utf-8 (base64-encode (string->bytes/utf-8 credentials)))]
[auth (string-append "Authorization: Basic " enc)]
[data (list (cons 'grant_type "client_credentials"))])
(post hc "/api/token" data auth)
(let-values ([(status-line header-list in-port) (http-conn-recv! hc)])
(displayln (port->string in-port)))))
(provide (all-defined-out))
main.rkt
#lang racket
(require "client.rkt")
(let ([client (spotify-client "<client-id>" "<client-secret>")]
[hc (hc)])
(gen-access-token hc client))
But the response I receive from the Spotify API is
{"error":"unsupported_grant_type","error_description":"grant_type must be client_credentials, authorization_code or refresh_token"}
.
This is odd because it's telling me that my grant_type is unsupported even though my grant_type is client_credentials (see when I call alist->form-urlencoded
on (list (cons 'grant_type "client_credentials"))
). What could be causing this?