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 OAuth2 SSO recover-success controller when the browser-only OAuth landing endpoint receives a JSON/Ajax request. Like its Azure/Google counterparts, this endpoint expects a full-page browser navigation following the OAuth2 provider redirect and rejects JSON requests up front.
Solutions
- Use plain browser navigation to the success URL; remove JSON/Ajax headers from the request.
- Do not call this endpoint programmatically; only follow the OAuth2 provider's redirect.
- Automate with a headless browser or a plain HTTP client that follows redirects without JSON headers.
- Inspect proxies/extensions that may convert the navigation into an Ajax request.
Example fix
// before
fetch('/sso/recover/success?token=...', { headers: { 'Accept': 'application/json' } });
// after
window.location.href = '/sso/recover/success?token=...'; Defensive patterns
Strategy: validation
Validate before calling
const accept = headers.get('Accept') ?? '';
if (accept.includes('application/json')) {
throw new Error('OAuth2 SSO success endpoint rejects JSON/Ajax requests; use browser navigation.');
} Type guard
function isPlainNavigation(headers) {
const h = new Headers(headers);
return !h.has('X-Requested-With') && !(h.get('Accept') ?? '').includes('application/json');
} Try / catch
try {
const res = await fetch(successUrl, { redirect: 'follow' });
if (res.status === 400 && (await res.text()).includes('Ajax/Json request not supported')) {
window.location.href = successUrl;
}
} catch (e) { window.location.href = successUrl; } Prevention
- Treat /sso/recover/success (OAuth2) as a browser-only redirect landing page.
- Do not fetch it with the passbolt JS API client's default JSON headers.
- Automate OAuth flows with a redirect-following browser, not fetch/XHR.
- Audit middleware/proxies that may add Ajax headers to the callback.
When it happens
Trigger: GET /sso/recover/success?token=... (OAuth2 variant) with Accept: application/json, X-Requested-With: XMLHttpRequest, or a JSON method-override header, e.g. when the URL is fetched by the passbolt JS API client or a script rather than loaded in the browser.
Common situations: curl/postman tests carrying JSON headers; a fetch/XHR call to the callback URL instead of following the OAuth redirect in the browser; browser extension or service worker rewriting the redirect.
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/283b16f1fc38a263.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/PassboltEe/SsoRecover/src/Controller/OAuth2/OAuth2RecoverSuccessController.php:45
class OAuth2RecoverSuccessController 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,
$eView on GitHub (pinned to 31c1bbc10f)