Announcements

Help Wizard

Step 1

NEXT STEP

FAQs

Please see below the most popular frequently asked questions.

Loading article...

Loading faqs...

VIEW ALL

Ongoing Issues

Please see below the current ongoing issues which are under investigation.

Loading issue...

Loading ongoing issues...

VIEW ALL

Spotify PKCE Auth Invalid Client Secret

Spotify PKCE Auth Invalid Client Secret

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

Reply
8 Replies

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.

Hello there! Have you succeeded solving the problem? The same issue happens to me now and I have no idea how to fix it. I double checked my code-verifier and code-challenge generation routines and body of request but still the error occurs. One thing I noticed however is that the code retrieved on the previous step can be successfully exchanged for an access token if I pass Authorization header just like in the authorization code flow and I'm not really sure if that is correct.

Hey! I just found out a way to solve this, at least it worked for me. Try resetting the client_secret through the dashboard. Probably, what could be happening is that the authorization API server thinks your are in the process of interchanging the authorization code for a pair of tokens, as in the standard authorization code flow, and by resetting the client_secret you invalidate any ongoing validation.

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:

https://github.com/tobika/spotify-auth-PKCE-example

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:

 

```

const { data, error } = await axios.post(
    {
        grant_type: 'refresh_token',
        refresh_token: MY_REFRESH_TOKEN,
        client_id: MY_SPOTIFY_CLIENT_ID,
        client_secret: MY_CLIENT_SECRET // We shouldn't have to do this
    },
    {
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded'
        }
    }
);

```

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

Suggested posts

Let's introduce ourselves!

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…

ModeratorStaff / Moderator/ 4 years ago  in Social & Random