CXone Client Credentials Grant Failing with 401 Despite Valid Keys

Just noticed that our CXone integration is failing during the token acquisition phase. We are building a React-based middleware service that needs to interact with the CXone API directly, bypassing the standard user-centric OAuth flows used in our Genesys Cloud desktop. The requirement is to use the client_credentials grant type to obtain a machine-to-machine access token for backend data synchronization.

I am constructing a POST request to the CXone token endpoint. The payload includes the client ID, client secret, and the grant type. However, the server consistently returns a 401 Unauthorized error. I have verified the credentials in the CXone Developer Portal multiple times. The request body is formatted as application/x-www-form-urlencoded. Here is the JavaScript fetch implementation I am using in our Node.js utility script:

const getToken = async () => {
 const params = new URLSearchParams();
 params.append('grant_type', 'client_credentials');
 params.append('client_id', process.env.CXONE_CLIENT_ID);
 params.append('client_secret', process.env.CXONE_CLIENT_SECRET);

 const response = await fetch('https://api.cxone.com/oauth2/token', {
 method: 'POST',
 headers: {
 'Content-Type': 'application/x-www-form-urlencoded',
 'Accept': 'application/json'
 },
 body: params
 });
 
 const data = await response.json();
 console.log('Token Response:', data);
 return data.access_token;
};

The error response payload is minimal:

{
 "error": "invalid_client",
 "error_description": "Client authentication failed"
}

I am accustomed to Genesys Cloud’s implicit grant with PKCE flows in the browser. This server-side flow feels different. Is there a specific scope required for the client credentials grant in CXone that I am missing? Or is the Content-Type header causing the authentication library to reject the body? I need a precise fix for this authentication code block.