passbolt/passbolt_api · error · BadRequestException

This is not a valid Ajax/Json request.

Error message

This is not a valid Ajax/Json request.

What it means

The MFA organization settings POST endpoint only accepts JSON (Ajax) requests. When the incoming request does not declare an Accept/Content-Type of JSON, CakePHP's `$this->request->is('json')` check fails and the controller throws a BadRequestException. It exists to prevent HTML form posts from silently being treated as API calls.

Solutions

  1. Send the request with `Content-Type: application/json` and `Accept: application/json` headers
  2. Append `.json` to the URL so CakePHP routes it through the JSON extension
  3. In tests, use `$this->postJson()` or set the request headers before dispatch

Example fix

// before
curl -X POST -d '{"providers":["totp"]}' https://passbolt/mfa/policies/settings.json
// after
curl -X POST -H 'Content-Type: application/json' -H 'X-CSRF-Token: <token>' \
  -d '{"providers":["totp"]}' https://passbolt/mfa/policies/settings.json
Defensive patterns

Strategy: validation

Validate before calling

const isJson = (opts) => (opts.headers['Content-Type'] || '').includes('application/json') && (opts.headers['Accept'] || '').includes('application/json');
if (!isJson(requestOptions)) throw new Error('MFA org settings endpoint requires JSON headers');

Type guard

function isJsonRequest(headers) {
  return typeof headers['Content-Type'] === 'string' && headers['Content-Type'].includes('application/json');
}

Try / catch

null

Prevention

When it happens

Trigger: POSTing to /mfa/policies/settings.json (or /mfa/policies/settings without .json) with Accept: text/html or missing Content-Type: application/json headers; submitting the MFA org-settings form via a plain HTML form post; a proxy or frontend client stripping the JSON Accept header.

Common situations: Calling the endpoint with curl without `-H 'Content-Type: application/json'`; older frontend code posting the legacy Duo settings format without the JSON content type; integration tests using `$this->post()` without `enableCsrfToken`/JSON headers.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17). Data as JSON: /api/errors/2a4853861f070b77. Report an issue: GitHub.

Appendix: source

Thrown at plugins/PassboltCe/MultiFactorAuthentication/src/Controller/OrgSettings/MfaOrgSettingsPostController.php:41

use Passbolt\MultiFactorAuthentication\Utility\MfaOrgSettingsDuoBackwardCompatible;

class MfaOrgSettingsPostController extends MfaController
{
    /**
     * Handle Org Settings POST request
     *
     * @throws \App\Error\Exception\CustomValidationException if the user provided data do not validate
     * @throws \Cake\Http\Exception\ForbiddenException if the user is not an admin
     * @throws \Cake\Http\Exception\BadRequestException if the request is not made using Ajax/Json
     * @param \Duo\DuoUniversal\Client|null $duoSdkClient Duo SDK Client
     * @return void
     */
    public function post(?Client $duoSdkClient = null): void
    {
        $this->User->assertIsAdmin();

        if (!$this->request->is('json')) {
            throw new BadRequestException(__('This is not a valid Ajax/Json request.'));
        }

        /** TODO: Remove this line and its class once the frontend has been updated to use the new format/names */
        $data = MfaOrgSettingsDuoBackwardCompatible::remapSetDuoSettings((array)$this->getRequest()->getData());

        $config = (new MfaOrgSettingsSetService())->setOrgSettings(
            $data,
            $this->User->getAccessControl(),
            $duoSdkClient
        );
        $this->success(__('The multi factor authentication settings for the organization were updated.'), $config);
    }
}

View on GitHub (pinned to 31c1bbc10f)