Building Secure Custom Credential Storage for MID Server Integrations

Dinethri ASP
Tera Contributor

If you've ever built a custom integration that needs the MID Server to authenticate against something ServiceNow doesn't have a built-in credential type for (a vendor API, a legacy device, a proprietary protocol), you've probably hit the same wall: the out-of-box credential table covers the common cases well, but the moment you need something slightly different, you're on your own. Here's a pattern that's worked well for handling custom credentials securely without reinventing encryption yourself.

 

Why you can't just add a field to the standard credential table

The built-in discovery_credentials table and its extensions are designed around known credential types (SSH, WMI, SNMP community strings, and so on). When your integration needs something outside those patterns, like a custom API key plus a secondary shared secret, or a credential format specific to one vendor's protocol, extending the base table gets messy fast. You end up fighting field definitions that were designed for a different purpose, and every platform upgrade becomes a risk to your customizations.

The cleaner approach is a dedicated custom credentials table, scoped to your application, purpose-built for exactly the fields your integration needs, and using the platform's own encryption primitives rather than rolling your own.

 

The core pieces

 

A custom table with a password2 field type. ServiceNow's password2 field type handles encryption and decryption for you using the instance's own encryption keys, so you're not storing anything in plaintext and you're not writing your own encryption logic. If your credential needs multiple secret values (an API key and a separate secret, for example), give each one its own password2 field rather than trying to concatenate secrets into one field and split them apart later. That concatenation trick looks convenient until someone changes a delimiter character and breaks decryption silently.

 

Global-scope decryption logic. This is the part people get stuck on. MID Server scripts that need to decrypt a password2 field have to call the decryption API from global scope, not from your application's scope, because of how the platform isolates encryption operations. If your integration is built in a scoped application (as most custom apps should be), you need a small global-scope Script Include whose only job is: receive a sys_id, decrypt the relevant field, hand back the plaintext value to the calling scoped code, and get out of the way. Keep this global-scope piece as small and single-purpose as possible. The smaller its surface area, the easier it is to review and the less risk there is of it becoming a general-purpose "decrypt anything" utility that outlives its original intent.

 

A Scripted REST API for MID Server retrieval. The MID Server doesn't have direct table access to your custom credentials table in the same way the instance does, so you need an endpoint the MID Server can call to retrieve (already-decrypted, over an authenticated and encrypted channel) the credential it needs at runtime. Design this endpoint to accept a specific identifier for which credential is needed, not a broad "give me all credentials" query. The narrower the request, the smaller the blast radius if something goes wrong with authentication on that endpoint.

 

Design decisions that matter more than they look like they do

 

Who can read the custom credentials table. It's easy to leave ACLs looser than they should be during development and forget to tighten them before go-live. Access to read (even encrypted) credential records should be restricted to the specific roles or service accounts that actually need it, not to anyone with general admin access to your scoped app.

 

Rotation, not just storage. A credential architecture that stores secrets securely but has no clean way to rotate them just delays the problem. Build the update path for a credential (new key issued by the vendor, old one revoked) into the design from day one, rather than treating it as an edge case you'll handle later. In practice, that usually means the custom table should support versioning or at least a clean single-record update pattern that doesn't require MID Server restarts to pick up.

 

Logging discipline. It's tempting, especially while debugging a new integration, to log the decrypted value "just to check it's coming through correctly." Don't. Even temporarily. Logs get retained longer than people expect, and a decrypted secret in a log file defeats the entire point of the architecture. Log the fact that decryption succeeded or failed, never the value itself.

 

Takeaway

None of this is about writing clever encryption code; the platform already gives you strong primitives for that. It's about respecting the boundaries those primitives come with (global scope for decryption, narrow and purpose-built endpoints, tight ACLs, and a rotation path from the start) rather than working around them because they're inconvenient in the moment. The integrations that cause security incidents later are usually the ones where someone worked around one of these boundaries under a deadline and never went back to fix it properly.

 

If you've built custom credential handling for a MID Server integration, I'd be curious how you approached rotation specifically. That's the part I see get skipped most often.

0 REPLIES 0