elsa-workflows/elsa-core · error · InvalidOperationException
Configuration connection
Error message
Configuration connection '{connectionKey}' supplies secret field '{name}' through AdapterSettings. Configure it through SecretBindings instead. What it means
Elsa's ExternalAuthentication module refuses to accept adapter settings JSON that populates fields declared as secrets in the adapter descriptor. Secret values must be supplied through SecretBindings (resolved via a resolver such as IConfiguration), never embedded in the plain AdapterSettings document, to keep secrets out of stored configuration. ThrowIfContainsDeclaredSecret is a guard that fails fast when a configuration connection's settings contain such a field.
Solutions
- Remove the secret field from the connection's AdapterSettings JSON.
- Add a SecretBindings entry for that field name referencing a resolver (e.g. a configuration path) instead.
- Store the actual secret value in the configuration provider (e.g. appsettings/IConfiguration) at the referenced path.
- If loading legacy data, migrate old inline secrets into SecretBindings before re-saving.
Example fix
// before
"adapterSettings": { "authority": "https://idp", "clientId": "app", "clientSecret": "s3cr3t" }
// after
"adapterSettings": { "authority": "https://idp", "clientId": "app" },
"secretBindings": { "clientSecret": { "resolverType": "Configuration", "reference": "ExternalAuth:MyIdp:ClientSecret" } } Defensive patterns
Strategy: validation
Validate before calling
// Before saving a connection
var names = AdapterSettingsSecretFieldGuard.GetSecretFieldNames(descriptor); // or RedactDeclaredSecrets as a probe
foreach (var name in names)
if (settings.TryGetProperty(name, out _))
throw new ArgumentException($"Move secret field '{name}' from AdapterSettings to SecretBindings."); Prevention
- Treat AdapterSettings as non-secret metadata only.
- Always put secrets in SecretBindings with a resolver reference.
- Run AdapterSettingsSecretFieldGuard.RedactDeclaredSecrets when echoing settings back to clients.
- Migrate legacy inline secrets once, at data-import time.
When it happens
Trigger: Occurs when saving or validating a connection whose AdapterSettings JSON object contains a property matching a secret field name declared by the adapter's ExternalAuthenticationAdapterDescriptor (GetSecretFieldNames), e.g. writing a connection where the client-secret key is placed directly in the settings payload instead of SecretBindings.
Common situations: Operators paste a full provider config (including the client secret) into the settings JSON exported from another tool; migrations or older connection formats stored the secret inline before SecretBindings existed; developers guess the settings schema and include secret keys.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- The configured secret binding is invalid.
- A configuration key is required.
- The OpenID Connect connection configuration is invalid.
- The secret field name must contain a letter or digit.
- The configured secret binding could not be resolved.
AI-assisted analysis of elsa-workflows/elsa-core@fe9217bdfa (2026-09-13).
Data as JSON: /api/errors/cb50ef72c01af9de.
Report an issue: GitHub.
Appendix: source
Thrown at src/modules/Elsa.ExternalAuthentication/Services/AdapterSettingsSecretFieldGuard.cs:20
using Elsa.ExternalAuthentication.Models;
namespace Elsa.ExternalAuthentication.Services;
/// <summary>
/// Prevents adapter setting fields that are declared as secret bindings from being persisted or returned as ordinary settings.
/// </summary>
public static class AdapterSettingsSecretFieldGuard
{
/// <summary>Throws when a descriptor-declared secret is supplied through an adapter settings document.</summary>
public static void ThrowIfContainsDeclaredSecret(JsonElement settings, ExternalAuthenticationAdapterDescriptor descriptor, string connectionKey)
{
if (settings.ValueKind != JsonValueKind.Object)
return;
var names = GetSecretFieldNames(descriptor);
var name = names.FirstOrDefault(name => settings.TryGetProperty(name, out _));
if (name is not null)
throw new InvalidOperationException($"Configuration connection '{connectionKey}' supplies secret field '{name}' through AdapterSettings. Configure it through SecretBindings instead.");
}
/// <summary>Returns a settings document with descriptor-declared secret fields redacted.</summary>
public static JsonElement RedactDeclaredSecrets(JsonElement settings, ExternalAuthenticationAdapterDescriptor descriptor)
{
if (settings.ValueKind != JsonValueKind.Object)
return settings.ValueKind == JsonValueKind.Undefined ? default : settings.Clone();
var names = GetSecretFieldNames(descriptor);
if (names.Count == 0 || !names.Any(name => settings.TryGetProperty(name, out _)))
return settings.Clone();
using var stream = new MemoryStream();
using (var writer = new Utf8JsonWriter(stream))
{
writer.WriteStartObject();
foreach (var property in settings.EnumerateObject())
{View on GitHub (pinned to fe9217bdfa)