{"record":{"id":"ca3981d063799192","repo":"passbolt/passbolt_api","slug":"ajax-json-request-not-supported-adfsrecoversuccesscontroller","errorCode":null,"errorMessage":"Ajax/Json request not supported.","messagePattern":"Ajax/Json request not supported\\.","errorType":"exception","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"plugins/PassboltEe/SsoRecover/src/Controller/Adfs/AdfsRecoverSuccessController.php","lineNumber":45,"sourceCode":"\nclass AdfsRecoverSuccessController extends AbstractSsoController\n{\n    /**\n     * @inheritDoc\n     */\n    public function beforeFilter(EventInterface $event)\n    {\n        parent::beforeFilter($event);\n        $this->Authentication->allowUnauthenticated(['ssoRecoverSuccess']);\n    }\n\n    /**\n     * @return void\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":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltEe/SsoRecover/src/Controller/Adfs/AdfsRecoverSuccessController.php#L27-L63","documentation":"The SSO recover success endpoint is a browser-redirect (web) endpoint that completes a recover flow started via an IdP. It only supports HTML navigation, so any request flagged as JSON/Ajax (Accept: application/json or X-Requested-With) is rejected with a BadRequestException.","triggerScenarios":"Calling /sso/recover/success (ADFS flow) with header Accept: application/json, or via fetch/XHR/Ajax instead of letting the browser follow the IdP redirect in a normal navigation.","commonSituations":"API clients or scripts trying to automate the recover flow over JSON; single-page apps fetching the redirect URL programmatically instead of opening it; curl tests adding -H 'Accept: application/json' (as passbolt's usual JSON API convention suggests).","solutions":["Access the endpoint via a normal browser navigation/redirect, not an Ajax/fetch call","Remove the Accept: application/json header (or send Accept: text/html) when testing with curl/Postman","Open the recovery link received by email in a browser so the SSO redirect chain completes natively","In an SPA, perform a full-page redirect (window.location = url) rather than fetching the URL"],"exampleFix":"// before (fails)\ncurl -H \"Accept: application/json\" https://passbolt.example.com/sso/recover/success?token=...\n// after\ncurl -H \"Accept: text/html\" -L https://passbolt.example.com/sso/recover/success?token=...","handlingStrategy":"fallback","validationCode":"if (isset($_SERVER['HTTP_ACCEPT']) && str_contains($_SERVER['HTTP_ACCEPT'], 'application/json')) {\n    // do not call the endpoint via JSON; navigate instead\n}","typeGuard":null,"tryCatchPattern":"try {\n    // full-page navigation to the recover success URL\n    window.location.href = ssoRecoverSuccessUrl;\n} catch (e) {\n    // fall back to opening in a new tab\n    window.open(ssoRecoverSuccessUrl, '_blank');\n}","preventionTips":["Never fetch SSO redirect endpoints with fetch/XHR — use top-level navigation","Omit JSON Accept headers when testing browser-only endpoints with curl/Postman","Treat /sso/recover/* routes as HTML-only in API clients","Document this constraint for any automation around recovery"],"tags":["sso","recover","bad-request","ajax","routing"],"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"}