bitwarden/server · error · BadRequestException

Invalid response from Teams.

Error message

Invalid response from Teams.

What it means

Thrown during the Teams OAuth callback when teamsService.ObtainTokenViaOAuth returns null or empty after exchanging the authorization code with Microsoft. The token exchange failed — code expired, invalid, or Microsoft returned an error. BadRequestException returns HTTP 400.

Source

Thrown at src/Api/Dirt/Controllers/TeamsIntegrationController.cs:119

        {
            throw new NotFoundException();
        }

        var callbackUrl = Url.RouteUrl(
            routeName: "TeamsIntegration_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 token = await teamsService.ObtainTokenViaOAuth(code, callbackUrl);
        if (string.IsNullOrEmpty(token))
        {
            throw new BadRequestException("Invalid response from Teams.");
        }

        var teams = await teamsService.GetJoinedTeamsAsync(token);

        if (!teams.Any())
        {
            throw new BadRequestException("No teams were found.");
        }

        var teamsIntegration = new TeamsIntegration(TenantId: teams[0].TenantId, Teams: teams);
        integration.Configuration = JsonSerializer.Serialize(teamsIntegration);
        await integrationRepository.UpsertAsync(integration);

        var location = $"/organizations/{integration.OrganizationId}/integrations/{integration.Id}";
        return Created(location, new OrganizationIntegrationResponseModel(integration));
    }

    [Route("integrations/teams/incoming")]

View on GitHub (pinned to e93b962371)

Solutions

  1. Exchange the authorization code immediately after receiving it.
  2. Verify Azure AD app client_id/client_secret are correct in server configuration.
  3. Ensure the redirect URI registered in Azure AD matches the deployed callback URL exactly.
  4. Add retry logic for transient network failures during token exchange.

Example fix

// before
var token = await teamsService.ObtainTokenViaOAuth(code, callbackUrl);
if (string.IsNullOrEmpty(token)) throw new BadRequestException("Invalid response from Teams.");

// after — capture and surface the underlying error
var result = await teamsService.ObtainTokenViaOAuthAsync(code, callbackUrl);
if (!result.Success)
{
    _logger.LogError("Teams token exchange failed: {Error}", result.ErrorDescription);
    throw new BadRequestException($"Teams OAuth failed: {result.Error}");
}
Defensive patterns

Strategy: retry

Validate before calling

// Pre-check Azure AD app configuration
if (string.IsNullOrWhiteSpace(_config["Teams:ClientId"]) ||
    string.IsNullOrWhiteSpace(_config["Teams:ClientSecret"]) ||
    string.IsNullOrWhiteSpace(_config["Teams:TenantId"]))
    throw new InvalidOperationException("Teams OAuth credentials not configured.");

Type guard

public static bool TeamsCredentialsConfigured(IConfiguration config) =>
    !string.IsNullOrEmpty(config["Teams:ClientId"]) &&
    !string.IsNullOrEmpty(config["Teams:ClientSecret"]);

Try / catch

int attempts = 0;
string? token = null;
while (attempts < 3 && string.IsNullOrEmpty(token))
{
    try { token = await _teamsService.ObtainTokenViaOAuth(code, callbackUrl); }
    catch (Exception ex) when (attempts < 2) { _logger.LogWarning("Teams token attempt {N} failed: {Ex}", attempts, ex.Message); }
    attempts++;
}
if (string.IsNullOrEmpty(token))
    return BadRequest("Teams OAuth token exchange failed. Please retry the authorization flow.");

Prevention

When it happens

Trigger: OAuth callback with a stale/already-used/invalid authorization code; Microsoft Entra ID (Azure AD) app credentials misconfigured; redirect URI mismatch; network failure during server-to-Microsoft token exchange.

Common situations: User delays authorization so the code expires; duplicate callback consumption; Azure AD app client secret rotated but not updated in config; redirect URI registered in Azure portal doesn't match the deployed callback; transient Microsoft Graph API outage.

Related errors


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