Getting a 401 Unauthorized when trying to grab an access token via the /oauth/token endpoint using raw Python requests.
We’ve got the integration set up in Genesys Cloud with the right scopes (conversation:read, routing:queue:read), and the client ID/secret are definitely correct since they work in Postman. The issue seems to be specific to how requests is formatting the body or headers.
Here’s the snippet:
import requests
url = "https://api.mypurecloud.com/oauth/token"
headers = {
"Content-Type": "application/x-www-form-urlencoded",
"Authorization": "Basic <base64_encoded_client_id_secret>"
}
payload = {
"grant_type": "client_credentials",
"scope": "conversation:read routing:queue:read"
}
response = requests.post(url, headers=headers, data=payload)
print(response.status_code)
print(response.text)
The response body is just {"error":"invalid_client","error_description":"The client credentials are invalid."}.
I’ve double-checked the base64 string by decoding it in a separate script, and it matches the ID and secret exactly. Clock skew isn’t an issue here since this is the initial token request, not a refresh.
Is there something weird with how requests handles the Basic auth header combined with the form-urlencoded body? I’ve seen some old forum posts mention issues with trailing slashes or specific content-type nuances, but application/x-www-form-urlencoded is standard for this grant type.
We’re running Python 3.9 on an EC2 instance in Tokyo, so network latency isn’t killing the request, it’s just rejecting it immediately.
Any ideas what’s breaking the auth handshake?