elsa-workflows/elsa-core · error · InvalidOperationException
External Authentication handle-hashing settings are…
Error message
External Authentication handle-hashing settings are required.
What it means
HmacExternalAuthenticationHandleHasher derives its HMAC-SHA-256 key from Elsa.ExternalAuthenticationOptions.HandleHashing at construction. When the bound HandleHashing section is null — meaning the options object was built without going through options binding/validation — GetKey refuses to run and throws this InvalidOperationException. The library throws instead of silently falling back so handle hashing is never keyed by an unexpected default.
Solutions
- Register the hasher through the module's standard service-registration extension (AddExternalAuthenticationCore / feature plumbing) so ExternalAuthenticationOptions is bound and validated by options infrastructure.
- Bind the configuration explicitly: services.AddOptions<ExternalAuthenticationOptions>().BindConfiguration("ExternalAuthentication") (or your section name) before the hasher resolves.
- In tests, populate the options: Options.Create(new ExternalAuthenticationOptions { HandleHashing = new ExternalAuthenticationHandleHashingOptions { SharedKeyBase64 = Convert.ToBase64String(RandomNumberGenerator.GetBytes(32)) } }) — or use the parameterless constructor meant for tests/dev.
- Verify the configuration section name matches ("ExternalAuthentication:HandleHashing") and the values are loaded in the environment being run.
Example fix
// before
services.AddSingleton<IExternalAuthenticationHandleHasher, HmacExternalAuthenticationHandleHasher>();
// after
services.AddOptions<ExternalAuthenticationOptions>()
.BindConfiguration("ExternalAuthentication");
services.AddSingleton<IExternalAuthenticationHandleHasher, HmacExternalAuthenticationHandleHasher>(); Defensive patterns
Strategy: validation
Validate before calling
// before constructing the hasher
var opts = serviceProvider.GetRequiredService<IOptions<ExternalAuthenticationOptions>>().Value;
if (opts.HandleHashing is null)
throw new InvalidOperationException("Bind ExternalAuthentication:HandleHashing before registering the handle hasher."); Type guard
static bool HasHandleHashing(ExternalAuthenticationOptions options) => options?.HandleHashing is not null;
Try / catch
try
{
var hasher = new HmacExternalAuthenticationHandleHasher(optionsAccessor);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("handle-hashing settings are required"))
{
logger.LogError(ex, "ExternalAuthentication:HandleHashing options section is not bound.");
throw; // fail fast — hashing with defaults would break handle lookups across restarts
} Prevention
- Always register the hasher via the module's service-registration extension instead of manual AddSingleton.
- Call BindConfiguration/ValidateDataAnnotations on ExternalAuthenticationOptions in every host that uses External Authentication.
- In tests, use Options.Create with a fully populated ExternalAuthenticationOptions or the parameterless test constructor.
- Add a startup health check that asserts options binding succeeded before serving traffic.
When it happens
Trigger: Constructing HmacExternalAuthenticationHandleHasher with IOptions<ExternalAuthenticationOptions> whose Value.HandleHashing is null, i.e. registering the hasher manually (e.g. services.AddSingleton<IExternalAuthenticationHandleHasher, HmacExternalAuthenticationHandleHasher>()) without binding the ExternalAuthentication options section, or calling the IOptions constructor in a test with an empty ExternalAuthenticationOptions instance.
Common situations: Hand-wiring the hasher in DI without services.AddOptions<ExternalAuthenticationOptions>().BindConfiguration(...); unit tests newing up IOptionsMock with Options.Create(new ExternalAuthenticationOptions()); a missing or misnamed configuration section so the HandleHashing property is never populated; upgrading Elsa versions where options wiring changed and custom DI registration no longer re-binds the section.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Register with configured before calling , or call with a…
- The console log provider registration is invalid.
- C# workflow expression execution is disabled. Set…
- The secret binding resolver is unavailable.
- The External Authentication shared handle-hashing key must…
AI-assisted analysis of elsa-workflows/elsa-core@fe9217bdfa (2026-09-13).
Data as JSON: /api/errors/95abe985b286ca10.
Report an issue: GitHub.
Appendix: source
Thrown at src/modules/Elsa.ExternalAuthentication/Services/HmacExternalAuthenticationHandleHasher.cs:44
/// </summary>
public HmacExternalAuthenticationHandleHasher(IOptions<ExternalAuthenticationOptions> options)
: this(GetKey(options.Value.HandleHashing))
{
}
private HmacExternalAuthenticationHandleHasher(byte[] key)
{
_key = key;
}
public string Hash(string value) => Convert.ToHexString(HMACSHA256.HashData(_key, Encoding.UTF8.GetBytes(value)));
public void Dispose() => CryptographicOperations.ZeroMemory(_key);
private static byte[] GetKey(ExternalAuthenticationHandleHashingOptions? options)
{
if (options is null)
throw new InvalidOperationException("External Authentication handle-hashing settings are required.");
if (string.IsNullOrWhiteSpace(options.SharedKeyBase64))
return RandomNumberGenerator.GetBytes(32);
try
{
var key = Convert.FromBase64String(options.SharedKeyBase64);
if (key.Length >= 32)
return key;
CryptographicOperations.ZeroMemory(key);
}
catch (FormatException)
{
// The options validator reports the actionable configuration error at startup.
}
throw new InvalidOperationException("The External Authentication shared handle-hashing key must be valid base64 containing at least 32 bytes.");View on GitHub (pinned to fe9217bdfa)