{"record":{"id":"1dafe71a4cf7805e","repo":"passbolt/passbolt_api","slug":"ajax-json-request-not-supported-1dafe7","errorCode":null,"errorMessage":"Ajax/Json request not supported.","messagePattern":"Ajax/Json request not supported\\.","errorType":"http","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"plugins/PassboltEe/SsoRecover/src/Controller/Google/GoogleRecoverSuccessController.php","lineNumber":47,"sourceCode":"{\n    /**\n     * @inheritDoc\n     */\n    public function beforeFilter(EventInterface $event)\n    {\n        parent::beforeFilter($event);\n\n        $this->Authentication->allowUnauthenticated(['ssoRecoverSuccess']);\n    }\n\n    /**\n     * @return void\n     * @throws \\League\\OAuth2\\Client\\Provider\\Exception\\IdentityProviderException\n     */\n    public function ssoRecoverSuccess(): void\n    {\n        if ($this->request->is('json')) {\n            throw new BadRequestException(__('Ajax/Json request not supported.'));\n        }\n\n        $this->User->assertNotLoggedIn();\n        $token = $this->getTokenFromUrlQuery();\n\n        try {\n            (new SsoAuthenticationTokenGetService())->getActiveNotExpiredOrFail($token, SsoState::TYPE_SSO_RECOVER);\n        } catch (RecordNotFoundException $e) {\n            throw new BadRequestException(\n                __('The authentication token does not exist or has been deleted.'),\n                null,\n                $e\n            );\n        } catch (CustomValidationException $e) {\n            throw new BadRequestException(\n                __('The authentication token has been expired.'),\n                null,\n                $e","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltEe/SsoRecover/src/Controller/Google/GoogleRecoverSuccessController.php#L29-L65","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\naxios.get('/sso/recover/success/google?token=...'); // sends Accept: application/json\n// after\nwindow.location.href = '/sso/recover/success/google?token=...';","handlingStrategy":"validation","validationCode":"const isJson = headers.get('Accept')?.includes('application/json');\nif (isJson) throw new Error('The Google SSO success endpoint must be loaded via browser navigation, not fetch/Ajax.');","typeGuard":"function isBrowserNavigation(init) {\n  const h = new Headers(init?.headers);\n  return !h.has('X-Requested-With') && !(h.get('Accept') ?? '').includes('application/json');\n}","tryCatchPattern":"try {\n  const res = await fetch(url, { redirect: 'follow' });\n  if (res.status === 400) {\n    window.location.href = url; // fall back to full navigation\n  }\n} catch (e) { window.location.href = url; }","preventionTips":["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."],"tags":["http","sso","bad-request","ajax"],"backgroundTag":"unsupported-operation","analyzedSha":"31c1bbc10f32808a607fa9bd81891e898779c0bc","analyzedAt":"2026-09-17T00:04:38.960Z","contentChangedAt":"2026-09-17T00:04:38.960Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}