passbolt/passbolt_api · warning · BadRequestException

The request is invalid.

Error message

The request is invalid.

What it means

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.

Solutions

  1. Restart the complete SSO login flow (stage1) to obtain a fresh token and retry verification promptly
  2. Verify the verification URL contains the exact keyId and token issued in the current flow, not from a prior attempt
  3. Check server logs for the chained exception to see the true underlying cause
  4. Ensure clocks are synced — token expiry checks depend on server time
  5. If using an extension/client, update it — older versions may generate incompatible tokens

Example fix

// before
// reusing a token from an aborted flow
await api.get(`/sso/keys/${oldKeyId}?token=${oldToken}`);
// after
const {keyId, token} = await startSsoStage1(); // fresh flow
await api.get(`/sso/keys/${keyId}?token=${token}`);
Defensive patterns

Strategy: try-catch

Validate before calling

// cannot pre-validate the token server-side; ensure token and keyId are from the CURRENT stage1 response
if (!currentFlowToken || !currentFlowKeyId) throw new Error('Start a fresh SSO stage1 flow before verifying the key');

Try / catch

try {
  await verifySsoKey(keyId, token);
} catch (e) {
  if (e.response?.status === 400) {
    // generic by design: restart the full SSO flow for a fresh token; check server logs for details
  } else if (e.response?.status === 404) {
    // key could not be found
  }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17). Data as JSON: /api/errors/b9c20d2d788310e3. Report an issue: GitHub.

Appendix: source

Thrown at plugins/PassboltEe/Sso/src/Controller/Keys/SsoKeysGetController.php:67

     * @return void
     */
    public function get(string $keyId, string $userId, string $token): void
    {
        $this->User->assertNotLoggedIn();

        try {
            $user = (new UserGetService())->getActiveNotDeletedNotDisabledOrFail($userId);
            $uac = new ExtendedUserAccessControl(
                Role::GUEST,
                $userId,
                $user->username,
                $this->User->ip(),
                $this->User->userAgent()
            );
            $key = (new SsoKeysGetService())->get($uac, $token, $keyId);
        } catch (BadRequestException $exception) {
            // Hide error details to prevent enumerations
            throw new BadRequestException(__('The request is invalid.'), 400, $exception);
        } catch (RecordNotFoundException $exception) {
            throw new NotFoundException(__('The key could not be found'), 404, $exception);
        }

        $this->success(__('The operation was successful'), $key);
    }
}

View on GitHub (pinned to 31c1bbc10f)