bitwarden/server · error · BadRequestException

Unable to build callback Url

Error message

Unable to build callback Url

What it means

Thrown during Slack OAuth initiation when Url.RouteUrl returns null or empty for route name 'SlackIntegration_Create'. This means the ASP.NET routing system could not resolve the named route to build the callback URL. BadRequestException surfaces as HTTP 400. The callback URL is essential for the OAuth redirect flow.

Source

Thrown at src/Api/Dirt/Controllers/SlackIntegrationController.cs:39

    TimeProvider timeProvider) : Controller
{
    [HttpGet("{organizationId:guid}/integrations/slack/redirect")]
    public async Task<IActionResult> RedirectAsync(Guid organizationId)
    {
        if (!await currentContext.OrganizationOwner(organizationId))
        {
            throw new NotFoundException();
        }

        string? callbackUrl = Url.RouteUrl(
            routeName: "SlackIntegration_Create",
            values: null,
            protocol: currentContext.HttpContext.Request.Scheme,
            host: currentContext.HttpContext.Request.Host.ToUriComponent()
        );
        if (string.IsNullOrEmpty(callbackUrl))
        {
            throw new BadRequestException("Unable to build callback Url");
        }

        var integrations = await integrationRepository.GetManyByOrganizationAsync(organizationId);
        var integration = integrations.FirstOrDefault(i => i.Type == IntegrationType.Slack);

        if (integration is null)
        {
            // No slack integration exists, create Initiated version
            integration = await integrationRepository.CreateAsync(new OrganizationIntegration
            {
                OrganizationId = organizationId,
                Type = IntegrationType.Slack,
                Configuration = null,
            });
        }
        else if (integration.Configuration is not null)
        {
            // A Completed (fully configured) Slack integration already exists, throw to prevent overriding

View on GitHub (pinned to e93b962371)

Solutions

  1. Verify the route named 'SlackIntegration_Create' is registered (check the controller's [Route] attribute matches the routeName argument).
  2. Ensure UseForwardedHeaders or similar middleware is configured so Request.Scheme and Request.Host are correct behind a proxy.
  3. Check that ASP.NET routing middleware (app.UseRouting()/UseEndpoints) is properly wired in startup.
  4. If the environment changed, confirm the application base path and host configuration.

Example fix

// before — relies on Url.RouteUrl which can return null
string? callbackUrl = Url.RouteUrl("SlackIntegration_Create", ...);

// after — fallback to a configured base URL
var baseUri = _config["BaseUrl"] ?? throw new InvalidOperationException("BaseUrl not configured");
string callbackUrl = $"{baseUri}/integrations/slack/callback";
Defensive patterns

Strategy: try-catch

Validate before calling

// Cannot fully validate client-side; check route registration at startup
dotnet run  // Observe if route 'SlackIntegration_Create' resolves
// In integration tests:
[Fact] public void SlackRouteRegistered() {
    var url = _urlHelper.RouteUrl("SlackIntegration_Create");
    Assert.NotNull(url);
}

Type guard

public static bool IsCallbackUrlBuildable(IUrlHelper urlHelper) =>
    !string.IsNullOrEmpty(urlHelper.RouteUrl("SlackIntegration_Create"));

Try / catch

try
{
    await _slackService.InitiateOAuthAsync(orgId);
}
catch (BadRequestException ex) when (ex.Message.Contains("callback Url"))
{
    _logger.LogCritical("Slack callback route misconfigured. Verify routing and forwarded headers.");
    return Problem("Slack integration is not properly configured on the server.");
}

Prevention

When it happens

Trigger: GET/POST initiating Slack OAuth flow where the route 'SlackIntegration_Create' is not registered, misnamed, or the routing middleware is not configured. Can also occur if the request scheme/host are unavailable (e.g., behind a misconfigured reverse proxy that strips Host headers).

Common situations: Deploying to a new environment where route registration changed; reverse proxy (nginx/ALB) not forwarding X-Forwarded-Host/X-Forwarded-Proto headers so Url helper cannot reconstruct the URL; renaming the route attribute without updating the routeName parameter; running behind a load balancer without UseForwardedHeaders middleware.

Related errors


AI-assisted analysis of bitwarden/server@e93b962371 (2026-08-13). Data as JSON: /api/errors/ba67a50926ba4f26. Report an issue: GitHub.