Long-lived OAuth token for CI/CD pipeline keeps expiring

Setting up an OpenTelemetry collector job in our CI/CD pipeline to trace Data Action latency. The pipeline runs in an ephemeral environment, so I can’t use the standard refresh token flow with a persistent storage for the refresh token. I’m trying to generate a long-lived access token using the client_credentials grant type, but the token expires after an hour.

Here’s the curl command I’m using in the script:

curl -X POST https://api.mypurecloud.com/oauth/token \
 -H 'Content-Type: application/x-www-form-urlencoded' \
 -d 'grant_type=client_credentials&client_id=MY_CLIENT_ID&client_secret=MY_CLIENT_SECRET'

The response returns a 200 OK, but the expires_in is 3600 seconds. The docs mention client_credentials is for server-to-server, but I don’t see an option to extend the lifetime. I tried adding scope=api:all, but that doesn’t change the expiration time.

Environment specs:

  • Genesys Cloud org with MFA disabled for the service account
  • Using a dedicated API user with api:all scope
  • CI/CD runner is GitHub Actions

Is there a way to get a token that lasts longer than an hour for this use case? Or do I have to implement a token refresh loop in the collector code?

The client_credentials grant type is explicitly designed for machine-to-machine auth without a user context, and Genesys Cloud enforces a strict 1-hour TTL on those tokens. You can’t extend that window via the API. The standard workaround for ephemeral CI/CD jobs isn’t fighting the expiration, it’s automating the refresh.

If you’re stuck in a pipeline without persistent storage for a refresh token, you need to generate the access token on-demand at the start of your job step, or use a service account with a very short-lived token and handle the retry logic in your collector config.

Here’s the standard flow for a fresh token in a bash script. Make sure your client ID and secret are injected as environment variables, not hardcoded.

#!/bin/bash
# Get fresh access token for CI/CD
RESPONSE=$(curl -s -X POST "https://api.mynice.com/oauth/token" \
 -H "Content-Type: application/x-www-form-urlencoded" \
 -d "grant_type=client_credentials&client_id=${NICE_CLIENT_ID}&client_secret=${NICE_CLIENT_SECRET}")

ACCESS_TOKEN=$(echo $RESPONSE | jq -r '.access_token')

# Verify token validity before proceeding
if [ -z "$ACCESS_TOKEN" ]; then
 echo "Failed to acquire access token"
 exit 1
fi

# Use the token in your OpenTelemetry config or subsequent API calls
export GENESYS_ACCESS_TOKEN=$ACCESS_TOKEN

If your collector supports dynamic config reloading, you can trigger a token refresh every 50 minutes. Otherwise, wrap your data collection logic in a retry block that catches 401 Unauthorized and re-fetches the token. Don’t try to cache it across pipeline runs. The overhead of a fresh POST /oauth/token call is negligible compared to debugging stale token errors. Just ensure your client has the admin:api scope if you’re pulling system-level metrics.