elsa-workflows/elsa-core · error · InvalidOperationException

A required secret binding resolver is unavailable.

Error message

A required secret binding resolver is unavailable.

What it means

Thrown by GetSecretFingerprintAsync (reached via RefreshAsync) when no ISecretBindingResolver capable of resolving the connection's secret binding is registered in the service provider. It indicates a misconfigured external-authentication installation: the secret binding's resolver type was never registered or the binding references an unknown resolver.

Solutions

  1. Register the ISecretBindingResolver implementation referenced by the connection's secret binding in DI before issuing or refreshing tokens.
  2. Inspect the connection's secret binding and correct its ResolverType so it matches a registered resolver.
  3. Verify the Elsa.ExternalAuthentication feature setup registered all built-in secret binding resolvers.
Defensive patterns

Strategy: fallback

When it happens

Trigger: Thrown at src/modules/Elsa.ExternalAuthentication/Services/DefaultExternalAuthenticationTokenIssuer.cs:100 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of elsa-workflows/elsa-core@fe9217bdfa (2026-09-13). Data as JSON: /api/errors/99c6c3c2d4626c9f. Report an issue: GitHub.

Appendix: source

Thrown at src/modules/Elsa.ExternalAuthentication/Services/DefaultExternalAuthenticationTokenIssuer.cs:100

        return new(
            accessToken.Token,
            "Bearer",
            Math.Max(0, (long)(accessToken.ExpiresAt - now).TotalSeconds),
            refreshToken,
            Math.Max(0, (long)(session.RefreshExpiresAt - now).TotalSeconds),
            Math.Max(0, (long)(session.ExpiresAt - now).TotalSeconds));
    }

    private static string CreateRefreshToken(string sessionId) => $"{sessionId}.{Convert.ToBase64String(RandomNumberGenerator.GetBytes(32)).TrimEnd('=').Replace('+', '-').Replace('/', '_')}";
    private static string Hash(string token) => Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(token)));

    private async ValueTask<string> GetSecretFingerprintAsync(IDictionary<string, SecretBinding> bindings, CancellationToken cancellationToken)
    {
        var fingerprints = new List<string>();
        foreach (var (name, binding) in bindings)
        {
            var resolver = secretBindingResolvers.FirstOrDefault(x => string.Equals(x.Type, binding.ResolverType, StringComparison.Ordinal))
                ?? throw new InvalidOperationException("A required secret binding resolver is unavailable.");
            var resolved = await resolver.ResolveAsync(binding, cancellationToken);
            fingerprints.Add($"{name}:{resolved.GenerationFingerprint}");
            resolved.Value.Dispose();
        }
        return Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(string.Join("\n", fingerprints.OrderBy(x => x, StringComparer.Ordinal)))));
    }
}

View on GitHub (pinned to fe9217bdfa)