CXone client_credentials token returning 401 on POST /api/v2/oauth/token despite valid creds

I’m hitting a wall with the CXone API authentication. I need to spin up a background service that doesn’t rely on user sessions, so I’m trying to use the client_credentials grant type.

The docs say it’s supported, but every time I hit the token endpoint, I get a 401 Unauthorized.

Here’s the request I’m sending:

const axios = require('axios');

const getToken = async () => {
 const formData = new URLSearchParams();
 formData.append('grant_type', 'client_credentials');
 // I've verified these in the CXone Admin UI under API Access
 formData.append('client_id', 'my-app-client-id');
 formData.append('client_secret', 'my-app-secret');

 try {
 const response = await axios.post(
 'https://api.cxone.com/api/v2/oauth/token',
 formData,
 {
 headers: {
 'Content-Type': 'application/x-www-form-urlencoded',
 'Accept': 'application/json'
 }
 }
 );
 console.log('Token:', response.data.access_token);
 } catch (error) {
 console.error('Auth failed:', error.response.status, error.response.data);
 }
};

getToken();

The error response is just generic:

Auth failed: 401 { error: 'invalid_client', error_description: 'Bad client credentials' }

I’ve copied the ID and Secret directly from the UI. I even regenerated the secret to make sure it wasn’t a copy-paste whitespace issue. The app is enabled and active.

Is there a specific scope I need to attach to the request body? I tried adding scope=platform:conversation:view but it didn’t change anything. Also, the endpoint URL… is it definitely api.cxone.com or does it vary by region? I’m assuming the global endpoint since I can’t find a region-specific one in the JS SDK examples.

Feeling pretty dumb about this one since it’s supposed to be the simplest auth flow.

The 401 usually stems from Basic Auth header encoding. Ensure your Authorization header uses base64(client_id:client_secret). If that checks out, verify the app has oauth:client_credentials scope enabled in the developer console.

curl -X POST https://api.mypurecloud.com/api/v2/oauth/token \
 -H "Authorization: Basic <base64_encoded>" \
 -d "grant_type=client_credentials"