{"record":{"id":"c77792fa2a00acb8","repo":"passbolt/passbolt_api","slug":"this-is-not-a-valid-ajax-json-request-jwtlogincontroller","errorCode":null,"errorMessage":"This is not a valid Ajax/Json request.","messagePattern":"This is not a valid Ajax/Json request\\.","errorType":"exception","errorClass":"Cake\\Http\\Exception\\BadRequestException","httpStatus":400,"severity":"error","filePath":"plugins/PassboltCe/JwtAuthentication/src/Controller/JwtLoginController.php","lineNumber":55,"sourceCode":"    {\n        $this->Authentication->allowUnauthenticated([\n            'loginPost',\n        ]);\n\n        EventManager::instance()->on(new UpdateUserLastLoggedInListener());\n\n        parent::beforeFilter($event);\n    }\n\n    /**\n     * User login post action\n     *\n     * @return void\n     */\n    public function loginPost()\n    {\n        if (!$this->request->is('json')) {\n            throw new BadRequestException(__('This is not a valid Ajax/Json request.'));\n        }\n\n        $result = $this->Authentication->getResult();\n        if ($result->isValid()) {\n            $challenge = $result->getData()['challenge'];\n            $user = $result->getData()['user'];\n            $uac = new UserAccessControl($user['role']['name'], $user['id']);\n            UserAction::getInstance()->setUserAccessControl($uac);\n\n            $event = new Event(UpdateUserLastLoggedInListener::EVENT_USER_LOGIN_SUCCESS, $this, ['user' => $user]);\n            $this->getEventManager()->dispatch($event);\n\n            $this->success(__('The authentication was a success.'), compact('challenge'));\n        } else {\n            $message = __('The authentication failed.') . ' ';\n            switch ($result->getStatus()) {\n                case Result::FAILURE_CREDENTIALS_MISSING:\n                    $message .= __('The credentials are missing.');","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltCe/JwtAuthentication/src/Controller/JwtLoginController.php#L37-L73","documentation":"Thrown by JwtLoginController::loginPost when the incoming request is not detected as a JSON request. The JWT login endpoint only accepts JSON bodies (and expects the GPGAuth headers); any other content type is rejected with a 400.","triggerScenarios":"POST to /auth/jwt/login without header 'Accept: application/json' (and/or without a JSON content type), e.g. form-encoded POST or a plain browser navigation.","commonSituations":"Calling the endpoint with curl without -H \"Content-Type: application/json\"; testing in a browser address bar; older HTTP clients that don't send Accept: application/json; proxies stripping headers.","solutions":["Send header 'Accept: application/json' with the request","Send the GPGAuth challenge headers (X-GPGAuth-Version, X-GPGAuth-Login-URL, etc.) and a JSON body","Ensure Content-Type is application/json for the request body","Use the official passbolt client/CLI which constructs the request correctly"],"exampleFix":"// before\ncurl -X POST https://passbolt.example.com/auth/jwt/login\n// after\ncurl -X POST https://passbolt.example.com/auth/jwt/login \\\n  -H \"Content-Type: application/json\" -H \"Accept: application/json\" \\\n  -H \"X-GPGAuth-Version: 1.3.0\" ...","handlingStrategy":"validation","validationCode":"if (!headers['Accept']?.includes('application/json')) headers['Accept'] = 'application/json';\nheaders['Content-Type'] = 'application/json';","typeGuard":null,"tryCatchPattern":"try { const r = await fetch(url, opts); } catch (e) { if (String(e.body?.message).includes('not a valid Ajax/Json request')) retryWithJsonHeaders(); }","preventionTips":["Always send Accept: application/json and Content-Type: application/json to passbolt API endpoints","Use the official passbolt SDK/CLI instead of hand-rolled requests","Verify headers survive proxies"],"tags":["http","json","bad-request","authentication"],"backgroundTag":"invalid-argument-format","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"}