bitwarden/server · error · BadRequestException

Duo configuration settings are not valid. Please re-check th

Error message

Duo configuration settings are not valid. Please re-check the Duo Admin panel.

What it means

BadRequestException is thrown in PUT /duo (PutDuo) when _duoUniversalTokenService.ValidateDuoConfiguration(clientSecret, clientId, host) returns false. The Duo configuration triple must be reachable and internally consistent (credentials match a real Duo Admin panel integration); otherwise the provider cannot issue or verify Universal prompts.

Source

Thrown at src/Api/Auth/Controllers/TwoFactorController.cs:250

    }

    [HttpDelete("duo")]
    [ProducesResponseType(StatusCodes.Status204NoContent)]
    public async Task<IActionResult> DeleteDuo([FromBody] TwoFactorDuoDeleteRequestModel model)
    {
        var user = await ValidateUserVerificationTokenAsync(model.UserVerificationToken, TwoFactorProviderType.Duo);
        await _userService.DisableTwoFactorProviderAsync(user, TwoFactorProviderType.Duo);
        return NoContent();
    }

    [HttpPut("duo")]
    public async Task<TwoFactorDuoUpdateResponseModel> PutDuo([FromBody] TwoFactorDuoUpdateRequestModel model)
    {
        var user = await ValidateUserVerificationTokenAsync(model.UserVerificationToken, TwoFactorProviderType.Duo);
        await ValidateUserHasPremiumAsync(user);
        if (!await _duoUniversalTokenService.ValidateDuoConfiguration(model.ClientSecret, model.ClientId, model.Host))
        {
            throw new BadRequestException(
                "Duo configuration settings are not valid. Please re-check the Duo Admin panel.");
        }

        model.ToUser(user);
        await _userService.UpdateTwoFactorProviderAsync(user, TwoFactorProviderType.Duo);
        return new TwoFactorDuoUpdateResponseModel(user);
    }

    [HttpPost("duo")]
    [Obsolete("This endpoint is deprecated. Use PUT /duo instead.")]
    public async Task<TwoFactorDuoUpdateResponseModel> PostDuo([FromBody] TwoFactorDuoUpdateRequestModel model)
    {
        return await PutDuo(model);
    }

    [HttpPost("~/organizations/{id}/two-factor/get-duo")]
    public async Task<TwoFactorOrganizationDuoResponseModel> GetOrganizationDuo(string id,
        [FromBody] SecretVerificationRequestModel model)

View on GitHub (pinned to e93b962371)

Solutions

  1. In the Duo Admin Panel, open the correct 'Univers2 / Universal Prompt' application and copy its Client ID, Client Secret, and API Hostname exactly.
  2. Ensure the host includes the full domain (e.g. api-XXXX.duosecurity.com).
  3. Confirm outbound network access from the server to the Duo API hostname.
  4. Regenerate the client secret if it may have been rotated/expired.

Example fix

// before
api.put('/users/two-factor/duo', { clientId: 'di-xxx', clientSecret: 'dh-yyy', host: 'XXXX' })
// after
api.put('/users/two-factor/duo', { clientId: 'di-xxx', clientSecret: 'dh-yyy', host: 'api-XXXX.duosecurity.com' });
Defensive patterns

Strategy: validation

Validate before calling

function validDuoConfig(c) { return /^di-/.test(c.clientId) && /^dh-/.test(c.clientSecret) && /^api-[a-z0-9]+\.duosecurity\.com$/i.test(c.host); }
if (!validDuoConfig(model)) throw new Error('Invalid Duo configuration');

Type guard

function isDuoConfig(c): c is DuoConfig { return typeof c?.clientId === 'string' && typeof c?.clientSecret === 'string' && typeof c?.host === 'string'; }

Try / catch

try { await api.put('/users/two-factor/duo', model); }
catch (e) {
  if (e.response?.status === 400 && /Duo configuration/.test(e.response.data?.message)) {
    throw new UserFacingError('Re-check the Duo Admin panel for the correct Client ID, Secret, and Host.');
  }
  throw e;
}

Prevention

When it happens

Trigger: PUT /api/users/two-factor/duo (TwoFactorController line 250) submitted with a ClientId/ClientSecret/Host that fail Duo-side validation (wrong secret, wrong integration type, unreachable host, malformed host like missing .duosecurity.com).

Common situations: Copying the wrong integration's credentials, using Duo Classic (Web SDK) credentials instead of a Universal Prompt application, a typo in the host, network egress blocking api-*.duosecurity.com, or the Duo application being suspended/deleted.

Related errors


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