{"record":{"id":"b9c20d2d788310e3","repo":"passbolt/passbolt_api","slug":"the-request-is-invalid-ssokeysgetcontroller","errorCode":null,"errorMessage":"The request is invalid.","messagePattern":"The request is invalid\\.","errorType":"http","errorClass":"BadRequestException","httpStatus":400,"severity":"warning","filePath":"plugins/PassboltEe/Sso/src/Controller/Keys/SsoKeysGetController.php","lineNumber":67,"sourceCode":"     * @return void\n     */\n    public function get(string $keyId, string $userId, string $token): void\n    {\n        $this->User->assertNotLoggedIn();\n\n        try {\n            $user = (new UserGetService())->getActiveNotDeletedNotDisabledOrFail($userId);\n            $uac = new ExtendedUserAccessControl(\n                Role::GUEST,\n                $userId,\n                $user->username,\n                $this->User->ip(),\n                $this->User->userAgent()\n            );\n            $key = (new SsoKeysGetService())->get($uac, $token, $keyId);\n        } catch (BadRequestException $exception) {\n            // Hide error details to prevent enumerations\n            throw new BadRequestException(__('The request is invalid.'), 400, $exception);\n        } catch (RecordNotFoundException $exception) {\n            throw new NotFoundException(__('The key could not be found'), 404, $exception);\n        }\n\n        $this->success(__('The operation was successful'), $key);\n    }\n}\n","sourceCodeStart":49,"sourceCodeEnd":75,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltEe/Sso/src/Controller/Keys/SsoKeysGetController.php#L49-L75","documentation":"Thrown by SsoKeysGetController::get() as a deliberately generic 400. Any BadRequestException raised while verifying the SSO key token (including errors surfaced by SsoKeysGetService::get()) is swallowed and replaced with 'The request is invalid.' to prevent attackers from enumerating valid tokens or key ids. The original exception is chained for server-side logging.","triggerScenarios":"GET /sso/keys with an invalid, expired, malformed, or already-consumed verification token, or a mismatched keyId/user combination — anything the underlying service rejects as BadRequest.","commonSituations":"User took too long between stage1 and token verification so the token expired; user restarted the SSO flow and reused an old token from a previous attempt; manually constructed verification URL with wrong key id; browser extension replaying stale tokens.","solutions":["Restart the complete SSO login flow (stage1) to obtain a fresh token and retry verification promptly","Verify the verification URL contains the exact keyId and token issued in the current flow, not from a prior attempt","Check server logs for the chained exception to see the true underlying cause","Ensure clocks are synced — token expiry checks depend on server time","If using an extension/client, update it — older versions may generate incompatible tokens"],"exampleFix":"// before\n// reusing a token from an aborted flow\nawait api.get(`/sso/keys/${oldKeyId}?token=${oldToken}`);\n// after\nconst {keyId, token} = await startSsoStage1(); // fresh flow\nawait api.get(`/sso/keys/${keyId}?token=${token}`);","handlingStrategy":"try-catch","validationCode":"// cannot pre-validate the token server-side; ensure token and keyId are from the CURRENT stage1 response\nif (!currentFlowToken || !currentFlowKeyId) throw new Error('Start a fresh SSO stage1 flow before verifying the key');","typeGuard":null,"tryCatchPattern":"try {\n  await verifySsoKey(keyId, token);\n} catch (e) {\n  if (e.response?.status === 400) {\n    // generic by design: restart the full SSO flow for a fresh token; check server logs for details\n  } else if (e.response?.status === 404) {\n    // key could not be found\n  }\n}","preventionTips":["Always use the token/keyId from the most recent stage1 response; never cache across flows","Complete verification promptly to stay within token TTL","Sync server clocks to avoid spurious token expiry","Read server logs for the chained exception to diagnose the real cause","Update browser extensions/clients to the latest SSO protocol version"],"tags":["sso","token","bad-request","enumeration-protection"],"backgroundTag":"invalid-identifier","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"}