passbolt/passbolt_api · error · BadRequestException

The user id should be a valid UUID.

Error message

The user id should be a valid UUID.

What it means

This BadRequestException is thrown by SsoAuthenticationTokenGetService::getOrFail when an optional $userId argument is passed but is not a valid UUID. getOrFail looks up SSO authentication tokens by token, type and optionally user_id, so a malformed user id would produce an invalid query and is rejected up front by CakePHP's Validation::uuid().

Solutions

  1. Validate the user id with \Cake\Validation\Validation::uuid($userId) before calling getOrFail, or pass null instead of an empty/malformed value
  2. Fetch the user from the users table first and pass the resulting entity's id UUID
  3. Trim/sanitize the incoming identifier; confirm it is the 36-char UUID from the users table, not a username or external SSO identifier
  4. In tests, ensure fixtures use real UUIDs rather than short placeholder strings

Example fix

// before
$service->getOrFail($token, SsoAuthenticationToken::TYPE_SSO, $this->request->getQuery('user_id'));
// after
$userId = $this->request->getQuery('user_id');
if (!\Cake\Validation\Validation::uuid($userId)) {
    throw new BadRequestException(__('The user id should be a valid UUID.'));
}
$service->getOrFail($token, SsoAuthenticationToken::TYPE_SSO, $userId);
Defensive patterns

Strategy: validation

Validate before calling

use Cake\Validation\Validation;
if ($userId !== null && !Validation::uuid($userId)) {
    throw new \Cake\Http\Exception\BadRequestException('Invalid user id');
}

Type guard

function isValidUuid(?string $id): bool {
    return $id === null || \Cake\Validation\Validation::uuid($id);
}

Try / catch

try {
    $token = $service->getOrFail($token, $type, $userId);
} catch (\Cake\Http\Exception\BadRequestException $e) {
    // handle invalid token/user id input
}

Prevention

When it happens

Trigger: Calling getOrFail($token, $type, $userId) (directly or via getActiveNotExpiredOrFail, get, or activate) with a $userId that is null-safe set but not a UUID — e.g. an empty string '', an integer cast to string, a truncated ID, or raw user input passed through without validation.

Common situations: Controller layers forwarding unvalidated route/query parameters; passing a username or email instead of the users.id UUID; passing an empty string instead of null for 'no user'; copying IDs from logs with surrounding whitespace.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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

Appendix: source

Thrown at plugins/PassboltEe/Sso/src/Service/SsoAuthenticationTokens/SsoAuthenticationTokenGetService.php:67

    {
        $this->SsoAuthenticationTokens = $this->fetchTable('Passbolt/Sso.SsoAuthenticationTokens');
    }

    /**
     * @param string $token token
     * @param string $type type
     * @param string|null $userId uuid
     * @throws \Cake\Http\Exception\BadRequestException if the authentication token is invalid
     * @throws \Cake\Datasource\Exception\RecordNotFoundException if the authentication token cannot be found
     * @return \Passbolt\Sso\Model\Entity\SsoAuthenticationToken
     */
    public function getOrFail(string $token, string $type, ?string $userId = null): SsoAuthenticationToken
    {
        if (!Validation::uuid($token)) {
            throw new BadRequestException(__('The authentication token should be a valid UUID.'));
        }
        if (isset($userId) && !Validation::uuid($userId)) {
            throw new BadRequestException(__('The user id should be a valid UUID.'));
        }

        try {
            $where = [
                'token' => $token,
                'type' => $type,
                'active' => true,
            ];
            if (isset($userId)) {
                $where['user_id'] = $userId;
            }

            /** @var \Passbolt\Sso\Model\Entity\SsoAuthenticationToken $tokenEntity */
            $tokenEntity = $this->SsoAuthenticationTokens->find()->where($where)->firstOrFail();
        } catch (RecordNotFoundException $exception) {
            throw new RecordNotFoundException(__('The authentication token does not exist.'), 400, $exception);
        }

View on GitHub (pinned to 31c1bbc10f)