We've updated the ServiceNow Community Code of Conduct, adding guidelines around AI usage, professionalism, and content violations. Read more

Support Needed: OAuth Key Rotation Implementation

VenkataAviM
Tera Contributor

Hi All,

 

We are currently working on implementing an OAuth key rotation process required by a system we integrate with. The keys expire every 90 days, and we must either rotate them automatically or renew them manually before expiration.

 

Key Rotation Workflow:

  1. Call a reset/renew API endpoint – this returns an encrypted new secret.
  2. Decrypt the encrypted secret using the existing secret via an AES‑based decryption method.
  3. Store the renewed secret securely in our system.
  4. Use the renewed secret for future token generation and API calls.
  5. Handling possible errors such as invalid credentials or attempting rotation too frequently (there’s a cooldown period).

What We Need To Implement:

  • API call logic for secret renewal.
  • AES decryption logic for the encrypted secret.
  • Secure storage of the rotated secret.
  • Automatic renewal workflow (cron/job/script). Ensuring the process runs reliably before the 90‑day expiry.
  • Error handling for invalid credentials, missing fields, or cooldown violations. Respect cooldown rules — a short waiting period is required between reset attempts.

Please note that our ServiceNow instance is not supporting Java Packages, decryptAES and encryptAES methods so as to use for Decryption and Encryption logics.

 

Could anyone please suggest a possible approach or best practice to implement this OAuth Secret Renewal & Decryption Process??

 

Thanks,

Venkata Avinash.

2 REPLIES 2

HaimNizri
Tera Contributor

This is a solid use case for a combination of Scheduled Jobs and Script Includes. I've implemented similar OAuth rotation workflows and here's what's worked well for me.

For the AES decryption piece since you can't use the built-in methods, you'll need to leverage the CryptoJS approach through a REST call to an external microservice or use ServiceNow's Integration Hub. But honestly, the cleanest approach I've found is creating a simple external endpoint that handles just the decryption part and calling it from ServiceNow.

Here's the structure I'd recommend:

**Script Include for the core logic:**
```javascript
var OAuthRotationUtil = Class.create();
OAuthRotationUtil.prototype = {
initialize: function() {
this.cooldownTable = 'u_oauth_rotation_log'; // track attempts
this.secretTable = 'u_oauth_secrets'; // store current secrets
},

rotateSecret: function(integrationName) {
// Check cooldown first
if (this._isInCooldown(integrationName)) {
gs.warn('OAuth rotation in cooldown for: ' + integrationName);
return false;
}

try {
// Call reset API
var response = this._callResetAPI(integrationName);
var encryptedSecret = response.encrypted_secret;

// Decrypt via external service
var decryptedSecret = this._decryptSecret(encryptedSecret, integrationName);

// Store securely
this._storeSecret(integrationName, decryptedSecret);

this._logRotation(integrationName, 'success');
return true;

} catch (e) {
this._logRotation(integrationName, 'failed', e.message);
gs.error('OAuth rotation failed: ' + e.message);
return false;
}
}
};
```

For secure storage, I use a custom table with encrypted fields rather than system properties. Create a table like `u_oauth_secrets` with an encrypted string field for the actual secret.

The tricky part is the decryption without Java packages. What I've done successfully is create a lightweight Node.js microservice that handles the AES decryption and deploy it somewhere ServiceNow can reach it. Then use a REST Message to call it with the encrypted data and current secret.

For scheduling, create a Scheduled Job that runs daily and checks expiry dates. Something like:

```javascript
var util = new OAuthRotationUtil();
var gr = new GlideRecord('u_oauth_secrets');
gr.addQuery('expires', '<=', gs.daysAgoEnd(-7)); // 7 days before expiry
gr.query();

while (gr.next()) {
util.rotateSecret(gr.integration_name.toString());
}
```

The cooldown tracking is crucial — store each rotation attempt with timestamp in a separate table and check it before allowing new rotations.

One gotcha I learned the hard way: make sure your external decryption service has proper timeout handling. If it's slow or down, your scheduled job will hang and you might miss the rotation window.

Have you considered what your fallback plan is if the automatic rotation fails close to the expiry date? I usually set up email notifications when we're within 3 days of expiry without a successful rotation.

VenkataAviM
Tera Contributor

Hi @HaimNizri,

 

Thank You for your inputs.

 

Currently we had implemented 3 System Properties to store the Key, Secret and API Endpoint in them. In addition a Script Include to call these Key, Secret and API Endpoint and a Scheduled Job so as to make the implementation simple for this requirement.

 

Would you please suggest a simple Encryption and Decryption Logic to be implemented in the Script Include along with the Scheduled Job and to store the new secret in System Property.

 

Thanks,

Venkata Avinash.