Getting 401 when using refresh token from client credentials flow in CI pipeline

We are setting up a CI/CD pipeline for our custom agent desktop app and need a way to authenticate without storing static tokens in the repo. The goal is to generate a long-lived session that the pipeline can use for the duration of the build.

I have been trying to use the OAuth2 client credentials flow. The initial token request works fine, but the access token expires in 3600 seconds. I am trying to use the refresh_token returned in the response to get a new access token, but it fails with a 401 Unauthorized.

Here is the code I am using in our Node.js script:

const axios = require('axios');

async function getAccessToken(clientId, clientSecret) {
 const tokenUrl = 'https://api.mypurecloud.com/oauth/token';
 const params = new URLSearchParams();
 params.append('grant_type', 'client_credentials');
 params.append('client_id', clientId);
 params.append('client_secret', clientSecret);

 try {
 const response = await axios.post(tokenUrl, params, {
 headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
 });
 return response.data;
 } catch (error) {
 console.error('Token fetch failed:', error.response.data);
 throw error;
 }
}

async function refreshToken(refreshToken) {
 const tokenUrl = 'https://api.mypurecloud.com/oauth/token';
 const params = new URLSearchParams();
 params.append('grant_type', 'refresh_token');
 params.append('refresh_token', refreshToken);

 try {
 const response = await axios.post(tokenUrl, params, {
 headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
 });
 return response.data;
 } catch (error) {
 console.error('Refresh failed:', error.response.data);
 throw error;
 }
}

The error message from the refresh attempt is:

{
 "errors": [
 {
 "description": "Invalid refresh token",
 "code": "invalid_grant"
 }
 ]
}

I read somewhere that client credentials flow does not support refresh tokens in the same way as authorization code flow. Is there a different endpoint or grant type I should be using for a machine-to-machine scenario in a pipeline? Or do I just need to re-fetch the token every time the pipeline runs? We want to avoid rate limiting issues if the pipeline runs frequently.