Type in your question below and we'll check to see what answers we can find...
Loading article...
Submitting...
If you couldn't find any answers in the previous step then we need to post your question in the community and wait for someone to respond. You'll be notified when that happens.
Simply add some detail to your question and refine the title if needed, choose the relevant category, then post.
Before we can post your question we need you to quickly make an account (or sign in if you already have one).
Don't worry - it's quick and painless! Just click below, and once you're logged in we'll bring you right back here and post your question. We'll remember what you've already typed in so you won't have to do it again.
Please see below the most popular frequently asked questions.
Loading article...
Loading faqs...
Please see below the current ongoing issues which are under investigation.
Loading issue...
Loading ongoing issues...
Plan
Premium
Country
Canada
Device
Chrome. Macbook Pro 2013
Operating System
Mac OS X Catalina
My Question or Issue
I am trying to set up my web application to use the Proof Key for Code Exchange. However, when I try try to get the access_token by doing a POST request to https://accounts.spotify.com/api/token, I get the following error
error: "invalid_request"
error_description: "Invalid client secret"
This message does not make sense to me since the PKCE method does not require a client secret. This is what my javascript code looks like. The code is the authorization_code from the redirect callback and the codeVerifier is used for generating the challenge as described in the docs.
const fetchUrl = "https://accounts.spotify.com/api/token";
const fetchBody = {
client_id: process.env.SPOTIFY_CLIENT_ID,
grant_type: "authorization_code",
code: code,
redirect_uri: process.env.BASE_URL + "/spotify-callback",
code_verifier: codeVerifier,
};
const searchParams = Object.keys(fetchBody)
.map((key) => {
return encodeURIComponent(key) + "=" + encodeURIComponent(fetchBody[key]);
})
.join("&");
const response = await fetch(fetchUrl, {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: searchParams,
});
Please could I get some advice on what I'm doing wrong? I have read and reread the documentation several times but I cannot figure it out.
More info
For calculating the sha256: https://www.npmjs.com/package/js-sha256
For performing base64Url encoding: https://www.npmjs.com/package/base64url
For random string for code verifier: https://www.npmjs.com/package/crypto-random-string
I just got a proof-of-concept for PKCE running on my local machine. I'm using Axios, but the code's almost identical to yours. I don't think you want the parameters sent in "body". (Yes, I know that the documentation makes it seem that you must do this.)
My Axios call is like this:
const postConfig = {
headers: {
'content-type': 'application/x-www-form-urlencoded',
},
};
return await instance.post(path, qs.stringify(parameters), postConfig)
.catch(() => ({offline: true}));
Notice that the parameters are sent in the path.
My code that calls this looks like this:
const parameters = {
client_id: use.global.clientId,
grant_type: 'authorization_code',
code: local.getItem('code'),
redirect_uri: getRedirectUri() + location.pathname,
code_verifier: local.getItem('codeVerifier'),
};
return api.call('POST', 'https://accounts.spotify.com/api/token', parameters)
.then(response => {
const {access_token, expires_in, refresh_token} = response.data;
if (access_token)
setAccessToken(access_token);
if (expires_in)
setAccessTokenExpiresOn((Math.floor(Date.now() / 1000)) + expires_in);
if (refresh_token)
setRefreshToken(refresh_token);
});
Make sure that in your initial redirect request(step 2.), the code_challenge and code_challenge_method are specified correctly, otherwise the endpoint will assume you are trying to do the "regular" Authorization work flow. This is why it is expecting a client_secret.
In order to try out the PKCE authorization flow I created a little example repository.
Don't hesitate to try it out and compare with your project:
Just in case for anyone else that comes along: I'm still unable to refresh the token unless I also specify the client_secret in the request body. This should not be required, per both the PKCE spec as well as the Spotify documentation: https://developer.spotify.com/documentation/web-api/tutorials/refreshing-tokens. However, I can confirm it works with the following refresh code:
```
```
whereas it will NOT work without the client_secret on the above body.
This is a problem, since that means that any application that's only on the browser won't be able to refresh the token, since it cannot store the client_secret on the browser.
Is there any chance anyone from Spotify has any guidance on the above? Thanks so much ahead of time if you do 🙏
Henry
Just out of curiosity, did you try my repo that I posted on top of your question?
3 years ago this seemed to work fine without client secret. Haven't tried it since.
PS: Seriously spotify?
https://github dot com/tobika/spotify-auth-PKCE-example
The message body contains git hub dot com, which is not permitted in this community. Please remove this content before sending your post.
Hi Tobikabla,
Thanks for taking a look at such an old thread! When I had initially responded here, I had not tried your repo yet... apologies for the laziness. However, after a little more digging, I ran across this issue on the Supabase repo (github/supabase/auth/issues/1450), which I'm using, which also referenced your code. After I checked it out and got it running, I can confirm that I AM able to refresh the token without supplying the client_secret. Thank you for writing that and sharing it... you rock!! 🙂🙏
For anyone else that comes along, what this means is that the Spotify API is working correctly, by refreshing the token even when no client_secret is provided, as long as the PKCE flow was used initially correctly. If you're receiving the invalid request error when attempting to refresh, it seems like the problem is likely related to something going wrong in the original sign in attempt, causing Spotify to use the implicit flow (which requires a client_secret to refresh) rather than the PKCE flow (which does not require a client_secret to refresh). If you're using Supabase, consider taking a look at the link above.
Henry
Hey there you, Yeah, you! 😁 Welcome - we're glad you joined the Spotify Community! While you here, let's have a fun game and get…