Hey everyone,
I’m trying to implement the Authorization Code flow with PKCE for a single-page application that pulls WFM adherence data. We’re moving away from the implicit grant because the security team is pushing for better practices. I’ve got the initial authorization request working fine, and the browser redirects back with the code, but the token exchange is failing with a 400 Bad Request.
Here’s the sequence:
- Generate
code_verifierandcode_challengeusing SHA-256. - Send the user to
https://api.mypurecloud.com/oauth/authorizewith thecode_challenge. - Receive the
codein the callback. - Post to
https://api.mypurecloud.com/oauth/tokento get the access token.
The error response is pretty generic:
{
"error": "invalid_grant",
"error_description": "Bad verification code"
}
I’ve double-checked the code_verifier being sent in the POST body. It matches exactly what was used to generate the challenge. I’m using plain fetch in the browser. Here’s the payload I’m sending:
const tokenPayload = new URLSearchParams({
grant_type: 'authorization_code',
code: urlParams.get('code'),
code_verifier: storedCodeVerifier,
redirect_uri: 'http://localhost:3000/callback'
});
fetch('https://api.mypurecloud.com/oauth/token', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic ' + btoa(clientId + ':' + clientSecret)
},
body: tokenPayload
});
The client_id and client_secret are definitely correct since I copied them straight from the developer console. The redirect URI matches exactly. I’m wondering if there’s a specific format issue with the PKCE parameters or if Genesys requires something extra in the headers.
Has anyone else hit this ‘Bad verification code’ error when switching to PKCE? I’m stuck on this step.