401 after refresh token exchange, clock skew?

Hey folks.

We’ve got a C# service using the Genesys Cloud .NET SDK. It works fine for a while, then suddenly all API calls start throwing 401 Unauthorized. The logs show the refresh token flow triggers, a new access token is obtained, but the next request still fails with 401.

I’m thinking clock skew between our Azure Function host and the Genesys Cloud auth server. Our server time is synced, but maybe the token expiration calculation is off by a few seconds?

Here’s the relevant snippet from our token refresh handler:

var client = new Client("https://api.mypurecloud.com");
var request = new Request("/oauth/token", Method.POST);
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddParameter("grant_type", "refresh_token");
request.AddParameter("refresh_token", refreshToken);
request.AddParameter("client_id", clientId);
request.AddParameter("client_secret", clientSecret);

var response = await client.ExecuteTaskAsync(request);
if (response.StatusCode != HttpStatusCode.OK)
{
 throw new Exception($"Refresh failed: {response.Content}");
}

var tokenData = JsonConvert.DeserializeObject<TokenResponse>(response.Content);
// Save new tokens...

The response.StatusCode is 200, and the new token looks valid in the JSON payload. I even decoded the JWT and the exp claim is in the future. But when I use the new access token in the next API call (e.g., GET /api/v2/users/me), it returns 401.

Is there a known issue with the .NET SDK handling token refresh timing? Or should I manually add a buffer to the expiration time before attempting the refresh? We’re using version 3.2.1 of the SDK.

Any help is appreciated.

Clock skew is a classic headache, but the .NET SDK usually handles the nbf and exp claims pretty well. If you’re still seeing 401s right after a refresh, it’s likely the token isn’t being attached to the subsequent request correctly, or the refresh itself failed silently.

Check your PlatformClient instance. If you’re manually managing tokens, you might be hitting a race condition. The SDK’s Login method should handle the refresh cycle automatically if configured right. Try forcing a re-login instead of relying on the internal refresh loop if it’s acting up.

Here’s a quick snippet to reset the auth context in C#:

var platformClient = PlatformClientFactory.CreatePlatformClient();
await platformClient.Login(clientId, clientSecret);
// Ensure you're using the same instance for subsequent calls
var usersApi = new UsersApi(platformClient);

Also, verify your Azure Function’s system clock. Even a few seconds off can cause JWT validation failures on the Genesys side. Run timedatectl or check the Azure portal diagnostics. If the clock is synced, the issue is almost certainly in how the token is persisted or reused in your service.