elsa-workflows/elsa-core · error · InvalidOperationException
The broker authorization request is invalid.
Error message
The broker authorization request is invalid.
What it means
A validation guard in ValidateAuthorizationRequest (called from InitiateExternalAsync and InitiateLocalAsync): the authorization request does not meet the broker's invariants — for example a missing or malformed redirect/pkce parameter, or a flow-state element that failed construction — so the request is rejected as invalid before any outbound authorization call.
Solutions
- Re-initiate the broker authorization flow so a fresh, correctly-formed request is generated.
- Check that all required request parameters (connection id, redirect URI, state) were supplied by the caller.
- Verify the connection referenced by the request exists and is enabled before initiating.
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at src/modules/Elsa.ExternalAuthentication/Services/ExternalAuthenticationBroker.cs:539 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/c472bdea57dc4539.
Report an issue: GitHub.
Appendix: source
Thrown at src/modules/Elsa.ExternalAuthentication/Services/ExternalAuthenticationBroker.cs:539
var connection = await connectionRegistry.FindByIdAsync(transaction.TenantId, transaction.ConnectionId!, cancellationToken);
return connection is null || connection.IsShadowed || !connection.Connection.IsEnabled || connection.Connection.ArchivedAt is not null || !string.Equals(connection.Connection.MaterialRevision, transaction.ConnectionMaterialRevision, StringComparison.Ordinal)
? await CallbackOutcomeAsync(BrokerCallbackResult.Fail(BrokerErrorFactory.Create(BrokerErrorCategory.FlowChanged)), "logout", "callback", transaction.TenantId, connectionKey, cancellationToken)
: await CallbackOutcomeAsync(BrokerCallbackResult.Redirect(transaction.CallbackUri), "logout", "callback", transaction.TenantId, connectionKey, cancellationToken);
}
public async ValueTask<BrokerLogoutResult> ContinueLogoutAsync(string handle, CancellationToken cancellationToken = default)
{
var taken = await stateStore.TryTakeAsync<BrokerTransaction>("UpstreamLogoutContinue", Hash(handle), cancellationToken);
if (taken is not TakeResult<BrokerTransaction>.Taken { Value: var transaction } || !Uri.TryCreate(transaction.ReturnPath, UriKind.Absolute, out var navigation))
return await LogoutOutcomeAsync(BrokerLogoutResult.Fail(BrokerErrorFactory.Create(BrokerErrorCategory.InvalidRequest)), "continue", cancellationToken);
return await LogoutOutcomeAsync(BrokerLogoutResult.Navigate(navigation), "continue", cancellationToken);
}
private AuthenticationClient EnsureClient(string clientId) => options.Value.Clients.FirstOrDefault(x => x.IsEnabled && string.Equals(x.ClientId, clientId, StringComparison.Ordinal)) ?? throw new InvalidOperationException("Authentication client is unavailable.");
private static void ValidateAuthorizationRequest(BrokerAuthorizationRequest request, AuthenticationClient client)
{
if (!string.Equals(request.ResponseType, "code", StringComparison.Ordinal) || !string.Equals(request.CodeChallengeMethod, "S256", StringComparison.Ordinal) || !client.CallbackUris.Contains(request.RedirectUri) || !ClientReturnPathValidator.TryValidateForClient(request.ReturnPath, client.AllowedReturnPathPrefixes, out _))
throw new InvalidOperationException("The broker authorization request is invalid.");
}
private static bool VerifyPkce(string challenge, string? verifier) => !string.IsNullOrWhiteSpace(verifier) && string.Equals(challenge, Base64Url(SHA256.HashData(Encoding.ASCII.GetBytes(verifier))), StringComparison.Ordinal);
private static string CreateOpaqueValue() => Base64Url(RandomNumberGenerator.GetBytes(32));
private string Hash(string value) => handleHasher.Hash(value);
private static string Base64Url(byte[] value) => Convert.ToBase64String(value).TrimEnd('=').Replace('+', '-').Replace('/', '_');
private static Uri AppendCallbackParameters(Uri uri, string code, string? clientState)
{
var result = AppendQuery(uri, "code", code);
return string.IsNullOrWhiteSpace(clientState) ? result : AppendQuery(result, "state", clientState);
}
private static Uri AppendQuery(Uri uri, string key, string value) { var separator = string.IsNullOrEmpty(uri.Query) ? "?" : "&"; return new(uri + separator + Uri.EscapeDataString(key) + "=" + Uri.EscapeDataString(value), uri.IsAbsoluteUri ? UriKind.Absolute : UriKind.Relative); }
private async ValueTask<BrokerCallbackResult> FailTrustedCallbackAsync(BrokerTransaction transaction, BrokerErrorCategory category, CancellationToken cancellationToken)
{
var error = BrokerErrorFactory.Create(category);
return await CallbackOutcomeAsync(BrokerCallbackResult.Fail(error, AppendQuery(AppendQuery(transaction.CallbackUri, "error", error.Error), "correlation_id", error.CorrelationId)), "external", "callback", transaction.TenantId, transaction.ConnectionId, cancellationToken);
}
View on GitHub (pinned to fe9217bdfa)