Skip to content

Spotify PKCE. Error invalid client secret

I need to complete Authorization Code Flow with Proof Key for Code Exchange. In step 4, I get an error 400 - bad request {"error":"invalid_request","error_description":"Invalid client secret"}.

Why need to client secret if it is PKCE. What do I wrong? Do you have any idea?

Body request like


Example code verifier: xeJ7Sx1lyUr0A_DAomzewuGn8vNS2cd3ZF2odDlqHEqeYKpxjnYYhpHxOohoo7lf22VNImGiOy_PE07owmDn2VmTWvdKKQ

Example code challenge: N_yPRc_VC8JQJz5dYOuvvM-9cJLdAtEjJ9-lh8Xk_qI

And the same I see into request.

Step 1

Use PkceUtil class

class PkceUtil {

    private static final int PKCE_BASE64_ENCODE_SETTINGS = Base64.NO_WRAP | Base64.NO_PADDING | Base64.URL_SAFE;

    String generateCodeVerifier(){
        SecureRandom random = new SecureRandom();
        byte[] codeVerifier = new byte[40];
        return Base64.encodeToString(codeVerifier, PKCE_BASE64_ENCODE_SETTINGS);

    String generateCodeChallenge(String codeVerifier) {
        byte[] bytes = codeVerifier.getBytes(StandardCharsets.UTF_8);
        MessageDigest messageDigest = getMessageDigestInstance();
        if (messageDigest != null) {
            byte[] digest = messageDigest.digest();
            return Base64.encodeToString(digest, PKCE_BASE64_ENCODE_SETTINGS);
        return "";

    private MessageDigest getMessageDigestInstance(){
        try {
            return MessageDigest.getInstance("SHA-256");
        } catch (NoSuchAlgorithmException e) {
        return null;

Step 2

Use official android-sdk auth-lib by Spotify

private AuthorizationRequest getAuthRequestCode() {
    PkceUtil pkceUtil = new PkceUtil();
    codeVerifier = pkceUtil.generateCodeVerifier();
    codeChallenge = pkceUtil.generateCodeChallenge(codeVerifier);
    return new AuthorizationRequest.Builder(CLIENT_ID, AuthorizationResponse.Type.CODE, getRedirectUri())
            .setCustomParam("code_challenge_method", "S256")
            .setCustomParam("code_challenge", codeChallenge)

private String getRedirectUri() {
    return Uri.parse(REDIRECT_URI).toString();

Step 3 and 4

Get code and send request to exchange it

private void onAuthResponse(int resultCode, Intent intent){
    AuthorizationResponse response = AuthorizationClient.getResponse(resultCode, intent);
    switch (response.getType()) {
        case TOKEN:
        case CODE:
            SpotifyAuthApi api = new SpotifyAuthApi();
            SpotifyAuthService spotify = api.getService();

            Map<String, Object> map = new HashMap<>();
            map.put("client_id", CLIENT_ID);
            map.put("grant_type", "authorization_code");
            map.put("code", response.getCode());
            map.put("redirect_uri", getRedirectUri());
            map.put("code_verifier", codeVerifier);
            spotify.getAccessToken(map, new Callback<AuthorizationResponse>() {
                public void success(AuthorizationResponse authorizationResponse, Response response) {

                public void failure(RetrofitError error) {
                    // Error 400 - bad request
        case ERROR:

In order to send request use own AuthApi and AuthService with help Retrofit

public interface SpotifyAuthService {

    AuthorizationResponse getAccessToken(@FieldMap Map<String, Object> params);

    void getAccessToken(@FieldMap Map<String, Object> params, Callback<AuthorizationResponse> callback);


public class SpotifyAuthApi {

    private static final String SPOTIFY_ACCOUNTS_ENDPOINT = "";

    private final SpotifyAuthService mSpotifyAuthService;

    private class WebApiAuthenticator implements RequestInterceptor {
        public void intercept(RequestFacade request) {
            request.addHeader("content-type", "application/x-www-form-urlencoded");

    public SpotifyAuthApi() {
        Executor httpExecutor = Executors.newSingleThreadExecutor();
        MainThreadExecutor callbackExecutor = new MainThreadExecutor();
        mSpotifyAuthService = init(httpExecutor, callbackExecutor);

    private SpotifyAuthService init(Executor httpExecutor, Executor callbackExecutor) {
        final RestAdapter restAdapter = new RestAdapter.Builder()
                .setExecutors(httpExecutor, callbackExecutor)
                .setRequestInterceptor(new SpotifyAuthApi.WebApiAuthenticator())

        return restAdapter.create(SpotifyAuthService.class);

    public SpotifyAuthService getService() {
        return mSpotifyAuthService;



I’m not familiar with Spotify Android SDK library, but judging by this issue, it does not support PKCE authentication flow and I’m not sure if it creates a valid request when you set custom code_challenge and code_challenge_method parameters.

Make sure that this step (2) works, as otherwise the authorization endpoint assumes that you use the normal Authorization Code Flow and expects a client_secret (in step 4).