passbolt/passbolt_api · error · BadRequestException

Ajax/Json request not supported.

Error message

Ajax/Json request not supported.

What it means

Thrown by PingOneRecoverSuccessController::ssoRecoverSuccess when the incoming request has the JSON/Ajax content type. This endpoint is a browser redirect target from the SSO provider and must render an HTML page, so JSON requests are explicitly rejected with a 400.

Solutions

  1. Open the callback URL via normal browser navigation (full page redirect), not fetch/XHR
  2. Remove JSON Accept/Content-Type headers when testing with curl/Postman
  3. Ensure the SSO provider is configured to redirect the browser directly to this endpoint
  4. Use the JSON SSO endpoints (e.g. RecoverStartController) for programmatic flows instead

Example fix

// before
curl -H 'Accept: application/json' https://host/sso/recover/success/pingone?token=...
// after
curl -H 'Accept: text/html' https://host/sso/recover/success/pingone?token=...  # or open in browser
Defensive patterns

Strategy: validation

Validate before calling

const isJsonRequest = (init) =>
  (init?.headers?.Accept || '').includes('application/json') ||
  (init?.headers?.['Content-Type'] || '').includes('application/json');
if (isJsonRequest(myInit)) throw new Error('Callback must be a browser navigation, not JSON.');

Prevention

When it happens

Trigger: Calling the success endpoint with Accept/Content-Type indicating JSON (e.g. fetch/XHR, curl with Accept: application/json, or passbolt JS API style request headers) instead of a normal browser navigation.

Common situations: Developer tests the provider callback URL with curl or Postman using JSON headers; frontend code incorrectly routes the callback through XHR; browser extension or proxy alters Accept headers.

Related errors


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

Appendix: source

Thrown at plugins/PassboltEe/SsoRecover/src/Controller/PingOne/PingOneRecoverSuccessController.php:45

class PingOneRecoverSuccessController extends AbstractSsoController
{
    /**
     * @inheritDoc
     */
    public function beforeFilter(EventInterface $event)
    {
        parent::beforeFilter($event);
        $this->Authentication->allowUnauthenticated(['ssoRecoverSuccess']);
    }

    /**
     * @return void
     */
    public function ssoRecoverSuccess(): void
    {
        if ($this->request->is('json')) {
            throw new BadRequestException(__('Ajax/Json request not supported.'));
        }

        $this->User->assertNotLoggedIn();
        $token = $this->getTokenFromUrlQuery();

        try {
            (new SsoAuthenticationTokenGetService())->getActiveNotExpiredOrFail($token, SsoState::TYPE_SSO_RECOVER);
        } catch (RecordNotFoundException $e) {
            throw new BadRequestException(
                __('The authentication token does not exist or has been deleted.'),
                null,
                $e
            );
        } catch (CustomValidationException $e) {
            throw new BadRequestException(
                __('The authentication token has been expired.'),
                null,
                $e

View on GitHub (pinned to 31c1bbc10f)