{"record":{"id":"e3e59f52da9757de","repo":"elsa-workflows/elsa-core","slug":"authentication-client-is-unavailable","errorCode":null,"errorMessage":"Authentication client is unavailable.","messagePattern":"Authentication client is unavailable\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/modules/Elsa.ExternalAuthentication/Services/ExternalAuthenticationBroker.cs","lineNumber":535,"sourceCode":"        if (taken is not TakeResult<BrokerTransaction>.Taken { Value: var transaction })\n            return await CallbackOutcomeAsync(BrokerCallbackResult.Fail(BrokerErrorFactory.Create(taken is TakeResult<BrokerTransaction>.Expired ? BrokerErrorCategory.FlowExpired : BrokerErrorCategory.InvalidRequest)), \"logout\", \"callback\", null, connectionKey, cancellationToken);\n        if (!string.Equals(transaction.ConnectionKey, ConnectionRevisionCalculator.NormalizeKey(connectionKey), StringComparison.Ordinal))\n            return await CallbackOutcomeAsync(BrokerCallbackResult.Fail(BrokerErrorFactory.Create(BrokerErrorCategory.InvalidRequest)), \"logout\", \"callback\", transaction.TenantId, connectionKey, cancellationToken);\n        var connection = await connectionRegistry.FindByIdAsync(transaction.TenantId, transaction.ConnectionId!, cancellationToken);\n        return connection is null || connection.IsShadowed || !connection.Connection.IsEnabled || connection.Connection.ArchivedAt is not null || !string.Equals(connection.Connection.MaterialRevision, transaction.ConnectionMaterialRevision, StringComparison.Ordinal)\n            ? await CallbackOutcomeAsync(BrokerCallbackResult.Fail(BrokerErrorFactory.Create(BrokerErrorCategory.FlowChanged)), \"logout\", \"callback\", transaction.TenantId, connectionKey, cancellationToken)\n            : await CallbackOutcomeAsync(BrokerCallbackResult.Redirect(transaction.CallbackUri), \"logout\", \"callback\", transaction.TenantId, connectionKey, cancellationToken);\n    }\n\n    public async ValueTask<BrokerLogoutResult> ContinueLogoutAsync(string handle, CancellationToken cancellationToken = default)\n    {\n        var taken = await stateStore.TryTakeAsync<BrokerTransaction>(\"UpstreamLogoutContinue\", Hash(handle), cancellationToken);\n        if (taken is not TakeResult<BrokerTransaction>.Taken { Value: var transaction } || !Uri.TryCreate(transaction.ReturnPath, UriKind.Absolute, out var navigation))\n            return await LogoutOutcomeAsync(BrokerLogoutResult.Fail(BrokerErrorFactory.Create(BrokerErrorCategory.InvalidRequest)), \"continue\", cancellationToken);\n        return await LogoutOutcomeAsync(BrokerLogoutResult.Navigate(navigation), \"continue\", cancellationToken);\n    }\n\n    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.\");\n    private static void ValidateAuthorizationRequest(BrokerAuthorizationRequest request, AuthenticationClient client)\n    {\n        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 _))\n            throw new InvalidOperationException(\"The broker authorization request is invalid.\");\n    }\n    private static bool VerifyPkce(string challenge, string? verifier) => !string.IsNullOrWhiteSpace(verifier) && string.Equals(challenge, Base64Url(SHA256.HashData(Encoding.ASCII.GetBytes(verifier))), StringComparison.Ordinal);\n    private static string CreateOpaqueValue() => Base64Url(RandomNumberGenerator.GetBytes(32));\n\n    private string Hash(string value) => handleHasher.Hash(value);\n    private static string Base64Url(byte[] value) => Convert.ToBase64String(value).TrimEnd('=').Replace('+', '-').Replace('/', '_');\n    private static Uri AppendCallbackParameters(Uri uri, string code, string? clientState)\n    {\n        var result = AppendQuery(uri, \"code\", code);\n        return string.IsNullOrWhiteSpace(clientState) ? result : AppendQuery(result, \"state\", clientState);\n    }\n    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); }\n    private async ValueTask<BrokerCallbackResult> FailTrustedCallbackAsync(BrokerTransaction transaction, BrokerErrorCategory category, CancellationToken cancellationToken)\n    {","sourceCodeStart":517,"sourceCodeEnd":553,"githubUrl":"https://github.com/elsa-workflows/elsa-core/blob/fe9217bdfa0e27f0e09e45006eb6898f616e513d/src/modules/Elsa.ExternalAuthentication/Services/ExternalAuthenticationBroker.cs#L517-L553","documentation":"A guard in ExternalAuthenticationBroker's callback handling: the authentication client needed to complete the broker flow (e.g. the OIDC/OAuth client for the connection) could not be obtained — typically because the connection or its provider configuration is missing or disabled — so the callback is failed rather than processed.","triggerScenarios":"Thrown at src/modules/Elsa.ExternalAuthentication/Services/ExternalAuthenticationBroker.cs:535 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Verify the external authentication connection exists, is enabled, and its provider/client configuration is complete.","Re-initiate the broker flow after fixing the configuration; the in-flight transaction cannot proceed without a client.","Check that the authentication feature providing the client was registered and started."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"fe9217bdfa0e27f0e09e45006eb6898f616e513d","analyzedAt":"2026-09-13T20:32:34.702Z","contentChangedAt":"2026-09-13T20:32:34.702Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}