Can anyone explain why the token exchange endpoint is rejecting my PKCE code challenge verification?
I am implementing the Authorization Code flow with PKCE for a single-page application that needs to authenticate users against Genesys Cloud. The initial authorization request to /oauth2/authorize succeeds, and I receive the code and state parameters in the redirect URI. However, when I attempt to exchange this code for an access token using the /oauth2/token endpoint, the server responds with a 400 Bad Request. The error payload indicates "error": "invalid_grant" with the description "Bad verification code".
I am constructing the code verifier as a random 43-character string using secrets.token_urlsafe(32) and then creating the code challenge by hashing the verifier with SHA-256 and base64url-encoding the result without padding. I have verified that the hash matches when I decode it locally. The POST request body includes the grant type, client ID, redirect URI, code, and code verifier. I am using httpx for the HTTP client.
import httpx
import hashlib
import base64
import secrets
def get_code_challenge(verifier: str) -> str:
digest = hashlib.sha256(verifier.encode('ascii')).digest()
challenge = base64.urlsafe_b64encode(digest).decode('ascii').rstrip('=')
return challenge
verifier = secrets.token_urlsafe(32)
challenge = get_code_challenge(verifier)
# ... Authorization step happens here, receiving 'auth_code' ...
response = httpx.post(
"https://api.mypurecloud.com/oauth2/token",
data={
"grant_type": "authorization_code",
"client_id": "my_client_id",
"redirect_uri": "https://myapp.local/callback",
"code": auth_code,
"code_verifier": verifier
}
)
print(response.status_code)
print(response.json())
The token endpoint is definitely https://api.mypurecloud.com/oauth2/token. I have checked the time synchronization on the server, and it is within one minute of NTP. The code is used immediately after receipt. Is there a specific requirement for the client ID registration regarding PKCE that I might be missing, or is the hash encoding slightly off?