Most Acumatica integrations I inherit store their secrets the same way: a connection string or API key sitting in plain text inside a customization project's config, or worse, hardcoded in a C# constant that ships inside a compiled DLL. It works right up until someone needs to rotate a credential, audit who can see it, or explain to a security reviewer why an integration secret is readable by anyone with file access to the web server. Pulling that integration onto HashiCorp Vault (or Azure Key Vault, the pattern is nearly identical) fixes all three problems at once, but it takes some care to do inside Acumatica's plugin model.
Find every place a secret currently lives before you start
Before touching Vault, I inventory every place a given integration's credentials currently exist: a site-scoped custom setting DAC in the database, a web.config appSetting, a hardcoded string in an extension, and - the one people forget - Business Events action configuration, which frequently embeds webhook URLs with API keys baked into the query string. On one client audit I found the same expired API key still live in three of those four places, two of which nobody had touched in over a year.
Fetch secrets at call time, cache briefly, never persist to the DAC
The integration point is usually a graph extension or a processing screen that calls an external API. The secret should never land in a custom DAC field, even an encrypted one, if you can avoid it entirely - because a DAC field, however it's stored, tends to get pulled into GIs, exports, and support screenshots eventually. Fetch it from Vault at call time instead:
public class VaultSecretProvider
{
private static readonly MemoryCache _cache = new MemoryCache("VaultSecrets");
public static string GetSecret(string path, string key)
{
if (_cache.Get(path) is string cached) return cached;
var client = new VaultClient(new VaultClientSettings(
Environment.GetEnvironmentVariable("VAULT_ADDR"),
new AppRoleAuthMethodInfo(
Environment.GetEnvironmentVariable("VAULT_ROLE_ID"),
Environment.GetEnvironmentVariable("VAULT_SECRET_ID"))));
var secret = client.V1.Secrets.KeyValue.V2
.ReadSecretAsync(path: path).GetAwaiter().GetResult();
var value = secret.Data.Data[key].ToString();
_cache.Set(path, value, DateTimeOffset.UtcNow.AddMinutes(10));
return value;
}
}
The ten-minute cache matters: Vault is not designed to take a network round trip on every RowSelected or every scheduled processing run against a thousand-record batch. Cache briefly enough that a rotated secret propagates within minutes, long enough that you're not hammering Vault on every call.
Vault authentication needs its own credential to get started, and on IIS the honest answer is environment variables set at the app pool level, or better, Azure Key Vault references if you're already on Azure App Service, which avoids storing even the AppRole secret ID in a way IIS config inspection could expose. There is no fully secret-free bootstrap; the goal is minimizing what's stored in the application itself down to the one credential needed to reach the vault.
Not every credential needs Vault - pick the ones that matter
I don't route every setting through Vault; that turns a five-line integration into infrastructure. The bar I use: does this credential grant access to something outside the Acumatica instance itself (an external API, a cloud storage bucket, a payment gateway), and would its exposure be a genuine incident rather than an inconvenience? Internal Acumatica custom settings that only affect in-instance behavior stay as ordinary site-scoped settings. Anything crossing a trust boundary to a third-party system goes through Vault.
Wrapping up
The value of Vault in an Acumatica integration isn't encryption for its own sake - Acumatica already has field-level encryption for that - it's centralizing rotation, access auditing, and revocation for credentials that reach outside the instance. Inventory where a secret currently lives before assuming it lives in one place, fetch at call time with a short cache rather than persisting to a DAC, and reserve the extra plumbing for credentials that actually cross a trust boundary.
Independent software engineer in Nairobi specialising in Acumatica customisations, Laravel backends, and tax fiscalisation integrations across East and Southern Africa.