passbolt/passbolt_api · error · InvalidVerifyTokenException

Invalid user ID format.

Error message

Invalid user ID format.

What it means

Alongside the verify token, the JWT verify-token request must carry the UUID of the user the token belongs to. validateUserId checks the user ID with Cake's Validation::uuid and throws InvalidVerifyTokenException ('Invalid user ID format.') when it is not a well-formed UUID.

Solutions

  1. Send the actual passbolt user UUID (36-char, hyphenated) in the user_id field
  2. Fetch the correct user ID from the API (e.g. /users.json) instead of constructing one
  3. Regenerate the test fixture with a UUID via Text::uuid() or a UUID generator
  4. Verify the client is not URL-encoding or trimming the UUID before sending

Example fix

// before
const body = {user_id: '42', verify_token: token};
// after
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(userId)) {
  throw new Error('user_id must be a UUID');
}
const body = {user_id: userId, verify_token: token};
Defensive patterns

Strategy: validation

Validate before calling

const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
if (!UUID_RE.test(userId ?? '')) throw new Error('user_id must be a UUID');

Type guard

function isUuid(v: unknown): v is string {
  return typeof v === 'string' && /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(v);
}

Try / catch

try { await api.verifyToken(token, userId); } catch (e) { if (e.response?.status === 400 && /user ID/.test(e.message)) await refetchUserId(); else throw e; }

Prevention

When it happens

Trigger: Calling the verify-token endpoint (or validateToken()) with a user id that is missing from the UUID format: empty string, numeric ID from another system, email address, or a truncated/corrupted UUID.

Common situations: Client confuses username/email with user ID; a migration or import produced non-UUID identifiers; test fixtures use ids like '1' or 'user-id'; copy-paste dropped characters from the UUID.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


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

Appendix: source

Thrown at plugins/PassboltCe/JwtAuthentication/src/Service/VerifyToken/VerifyTokenValidationService.php:106

            !is_string($verifyToken) ||
            !Validation::uuid($verifyToken)
        ) {
            throw new InvalidVerifyTokenException(__('Invalid verify token format.'));
        }
    }

    /**
     * Assert verify token is a UUID
     *
     * @param string $userId User ID
     * @return void
     * @throws \Passbolt\JwtAuthentication\Error\Exception\VerifyToken\InvalidVerifyTokenException if the user ID is not a UUID.
     * @throws \Cake\ORM\Exception\PersistenceFailedException
     */
    protected function validateUserId(string $userId): void
    {
        if (!Validation::uuid($userId)) {
            throw new InvalidVerifyTokenException(__('Invalid user ID format.'));
        }
    }

    /**
     * Check that this token - userId pair does not exist.
     *
     * @param string $verifyToken Verify Token
     * @param string $userId User ID
     * @return void
     * @throws \Cake\Http\Exception\BadRequestException if the token has already been used.
     */
    protected function validateNonce(string $verifyToken, string $userId): void
    {
        $AuthenticationTokens = TableRegistry::getTableLocator()->get('AuthenticationTokens');
        $existingTokenWithSameValue = $AuthenticationTokens
            ->find()
            ->where([
                $AuthenticationTokens->aliasField('token') => $verifyToken,

View on GitHub (pinned to 31c1bbc10f)