Oauth client secret rotation strategy without service interruption

What’s the best way to rotate oauth client secrets for our terraform-managed genesys cloud orgs without causing downtime for our ci/cd pipelines and monitoring webhooks?

we are managing a large-scale deployment using terraform-provider-genesyscloud (v1.75.0+). the current setup uses a single genesyscloud_oauth_client resource. when we update the secret attribute, terraform forces a recreation of the resource (forces replacement), which invalidates the old secret immediately. this breaks any long-running processes or external services holding the previous token until they can fetch the new one, leading to transient 401 unauthorized errors.

i have reviewed the api docs and noticed that the platform supports multiple active secrets via the /api/v2/oauth/clients/{id}/secrets endpoint. however, i cannot find a direct terraform resource to manage multiple secrets for a single client simultaneously. the genesyscloud_oauth_client resource seems to only support a single secret string.

my proposed workaround is a manual api call sequence:

  1. generate a new secret via post /api/v2/oauth/clients/{id}/secrets
  2. update external config stores (vault/parameter store) with the new secret
  3. verify downstream services are using the new secret
  4. delete the old secret via delete /api/v2/oauth/clients/{id}/secrets/{secretId}

is there a supported terraform pattern or a specific api sequence that handles this gracefully? i want to avoid manual intervention in our gitops workflow.

here is the current terraform snippet causing the issue:

resource "genesyscloud_oauth_client" "api_client" {
 name = "ci-cd-service-account"
 redirect_uris = ["urn:ietf:wg:oauth:2.0:oob"]
 secret = var.oauth_client_secret # updating this forces recreation
}

any insights on managing secret rotation lifecycle within the terraform state or via companion api calls would be appreciated.

Make sure you avoid recreating the OAuth client resource. Use the API directly to rotate secrets while keeping the client ID stable.

resource "null_resource" "rotate_secret" {
 provisioner "local-exec" {
 command = "curl -X POST /api/v2/oauth/clients/${genesyscloud_oauth_client.main.id}/rotate"
 }
}

Forces replacement breaks pipelines.