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 Azure SSO recover-success controller when a client sends the request with a JSON/Ajax Accept or Content-Type header. The SSO recover success endpoint is a browser redirect target (full-page HTML flow) and is deliberately not part of the JSON API, so any JSON-formatted request is rejected immediately before any token validation.
Solutions
- Remove JSON-related headers (Accept: application/json, X-Requested-With, X-Http-Method-Override) and request the endpoint as a plain browser navigation/redirect.
- Do not invoke the recover-success URL from API code; only follow the OAuth2 provider redirect in a browser.
- If automating the flow, use a headless browser or follow redirects with a plain HTTP client that does not set JSON headers.
- If you landed here from the JS API, switch to the regular (non-JSON) fetch or window.location navigation.
Example fix
// before
await fetch('/sso/recover/success/azure?token=...', { headers: { 'Accept': 'application/json', 'X-Requested-With': 'XMLHttpRequest' } });
// after
window.location.href = '/sso/recover/success/azure?token=...'; Defensive patterns
Strategy: validation
Validate before calling
const url = new URL(successUrl, window.location.origin);
const isJsonRequest = headers.has('Accept') && headers.get('Accept').includes('application/json');
if (isJsonRequest) throw new Error('Use browser navigation, not a JSON request, for the SSO success endpoint.'); Type guard
function isAjaxHeader(headers) {
return headers instanceof Headers &&
(headers.get('X-Requested-With') === 'XMLHttpRequest' ||
(headers.get('Accept') ?? '').includes('application/json'));
} Try / catch
try {
const res = await fetch('/sso/recover/success/azure?token=' + token, { redirect: 'follow' });
if (res.status === 400 && (await res.text()).includes('Ajax/Json request not supported')) {
window.location.href = '/sso/recover/success/azure?token=' + token;
}
} catch (e) { /* network errors */ } Prevention
- Treat all /sso/recover/success/* endpoints as browser-only redirect targets.
- Strip passbolt JSON API default headers when hitting browser-flow endpoints.
- Never proxy the OAuth redirect through an Ajax/fetch call.
- Document that these endpoints return HTML, not JSON.
When it happens
Trigger: A client calls GET /sso/recover/success/azure (the OAuth2 redirect landing URL) with the 'X-Http-Method-Override' or Accept header indicating JSON (e.g. the passbolt JS API client default headers, Accept: application/json), or an Ajax/fetch call is made against this browser-only endpoint.
Common situations: Developers testing the SSO recover flow via curl/postman with passbolt's typical JSON headers, or a browser extension/script intercepting the OAuth redirect and re-issuing it as an Ajax request instead of a full navigation.
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/a85d5b94f33419a4.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/PassboltEe/SsoRecover/src/Controller/Azure/AzureRecoverSuccessController.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)