401 Unauthorized after token refresh — clock skew between servers

Dealing with a very strange bug here with the CXone OAuth flow. I am implementing an automated schedule sync service using Python. The initial POST /oauth/token succeeds, returning a valid access token and a refresh_token. I store the expires_in value and set an internal timer to refresh 60 seconds before expiry.

When the timer fires, I call the refresh endpoint. The server responds with HTTP 401 Unauthorized. The error payload is minimal:

{
 "error": "invalid_grant",
 "error_description": "Token has expired"
}

I verified the refresh_token is being sent correctly in the body. My local server clock is synced via NTP. However, I suspect the CXone auth server and my app server have a clock skew exceeding the JWT validation window. The documentation here mentions a 5-minute tolerance, but this error happens immediately upon refresh.

  1. How do I verify the exact server time of the CXone auth endpoint programmatically?
  2. Is there a header or endpoint that returns the current server time to adjust my local clock?
  3. Should I be ignoring expires_in and relying solely on 401 retries instead?

You might want to check at the token validation logic in your Python client. The 401 likely stems from a clock skew exceeding the server’s tolerance window. Ensure your system time syncs via NTP before calling platformClient.authClient.refreshAccessToken(). See OAuth Token Lifecycle for details on handling refresh drift.