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
- Send the actual passbolt user UUID (36-char, hyphenated) in the user_id field
- Fetch the correct user ID from the API (e.g. /users.json) instead of constructing one
- Regenerate the test fixture with a UUID via Text::uuid() or a UUID generator
- 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
- Always source user IDs from the API, not from usernames or emails
- Keep UUIDs intact through URL/storage handling
- Add client-side UUID validation in forms and SDKs
- Use consistent 36-char hyphenated UUID representation
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
- Invalid verify token format.
- The refresh token should be a valid UUID.
- The resource identifier should be a valid UUID.
- The user id is missing or invalid.
- The user ID should be a valid UUID.
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)