passbolt/passbolt_api · error · BadRequestException
Ajax/Json request not supported.
Error message
Ajax/Json request not supported.
What it means
This BadRequestException is thrown by the Google SSO recover-success controller when a request to the browser-only OAuth redirect landing endpoint arrives as JSON/Ajax. The endpoint is designed for full-page browser navigation after Google's OAuth callback, so JSON-formatted requests are rejected before token processing.
Solutions
- Request the endpoint with plain browser navigation; strip Accept: application/json and X-Requested-With headers.
- Never call the recover-success URL from API client code; let the OAuth2 provider's redirect land in the browser.
- If automating, use a headless browser (Playwright/Puppeteer) or a redirect-following client without JSON headers.
- Check proxies/extensions that may rewrite the redirect into an Ajax call.
Example fix
// before
axios.get('/sso/recover/success/google?token=...'); // sends Accept: application/json
// after
window.location.href = '/sso/recover/success/google?token=...'; Defensive patterns
Strategy: validation
Validate before calling
const isJson = headers.get('Accept')?.includes('application/json');
if (isJson) throw new Error('The Google SSO success endpoint must be loaded via browser navigation, not fetch/Ajax.'); Type guard
function isBrowserNavigation(init) {
const h = new Headers(init?.headers);
return !h.has('X-Requested-With') && !(h.get('Accept') ?? '').includes('application/json');
} Try / catch
try {
const res = await fetch(url, { redirect: 'follow' });
if (res.status === 400) {
window.location.href = url; // fall back to full navigation
}
} catch (e) { window.location.href = url; } Prevention
- Never call /sso/recover/success/google from API client code; follow the Google OAuth redirect in a browser.
- Remove default JSON Accept headers for browser-flow URLs.
- Use a headless browser for automated testing of the OAuth callback.
- Check extensions/proxies that rewrite navigations into XHR.
When it happens
Trigger: GET /sso/recover/success/google?token=... with Accept: application/json or Ajax markers (X-Requested-With: XMLHttpRequest), typically from the passbolt JS client or a fetch/axios call instead of a browser redirect.
Common situations: Testing the Google SSO recovery URL via curl/postman with default passbolt JSON headers; a script or service worker intercepting the OAuth callback and re-issuing it as an Ajax request.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Ajax/Json request not supported.
- Ajax/Json request not supported.
- Ajax/Json request not supported.
- Ajax/Json request not supported.
- The email is required in URL parameters.
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/1dafe71a4cf7805e.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/PassboltEe/SsoRecover/src/Controller/Google/GoogleRecoverSuccessController.php:47
{
/**
* @inheritDoc
*/
public function beforeFilter(EventInterface $event)
{
parent::beforeFilter($event);
$this->Authentication->allowUnauthenticated(['ssoRecoverSuccess']);
}
/**
* @return void
* @throws \League\OAuth2\Client\Provider\Exception\IdentityProviderException
*/
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,
$eView on GitHub (pinned to 31c1bbc10f)