{"record":{"id":"99d95ba28e983656","repo":"passbolt/passbolt_api","slug":"invalid-verify-token-format","errorCode":null,"errorMessage":"Invalid verify token format.","messagePattern":"Invalid verify token format\\.","errorType":"http","errorClass":"InvalidVerifyTokenException","httpStatus":400,"severity":"error","filePath":"plugins/PassboltCe/JwtAuthentication/src/Service/VerifyToken/VerifyTokenValidationService.php","lineNumber":91,"sourceCode":"        }\n    }\n\n    /**\n     * Assert verify token is a UUID\n     *\n     * @param mixed $verifyToken token\n     * @return void\n     * @throws \\Passbolt\\JwtAuthentication\\Error\\Exception\\VerifyToken\\InvalidVerifyTokenException if the format is not valid.\n     * @throws \\Cake\\ORM\\Exception\\PersistenceFailedException\n     */\n    protected function validateFormat(mixed $verifyToken): void\n    {\n        if (\n            !isset($verifyToken) ||\n            !is_string($verifyToken) ||\n            !Validation::uuid($verifyToken)\n        ) {\n            throw new InvalidVerifyTokenException(__('Invalid verify token format.'));\n        }\n    }\n\n    /**\n     * Assert verify token is a UUID\n     *\n     * @param string $userId User ID\n     * @return void\n     * @throws \\Passbolt\\JwtAuthentication\\Error\\Exception\\VerifyToken\\InvalidVerifyTokenException if the user ID is not a UUID.\n     * @throws \\Cake\\ORM\\Exception\\PersistenceFailedException\n     */\n    protected function validateUserId(string $userId): void\n    {\n        if (!Validation::uuid($userId)) {\n            throw new InvalidVerifyTokenException(__('Invalid user ID format.'));\n        }\n    }\n","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltCe/JwtAuthentication/src/Service/VerifyToken/VerifyTokenValidationService.php#L73-L109","documentation":"Passbolt's JWT verify-token endpoint requires the verify token to be a UUID string. VerifyTokenValidationService::validateFormat rejects any missing, non-string, or non-UUID token value with InvalidVerifyTokenException, which the client sees as 'Invalid verify token format.' This guards the nonce lookup against malformed input before any database query runs.","triggerScenarios":"POST/GET to the JWT verify-token endpoint with a missing, empty, non-string (e.g. array/integer), or non-UUID verify token; calling VerifyTokenValidationService::validateToken() directly with a malformed token as the second argument.","commonSituations":"Client code truncates or mangles the token when storing it in localStorage; a test harness passes a placeholder like 'test-token' instead of a UUID; the token is sent URL-decoded/percent-encoded or wrapped in extra characters; a very old client version sends a differently formatted token.","solutions":["Generate the verify token as a valid UUID (e.g. the value issued by the server / Text::uuid()) and resend the request","Check the client is actually reading the stored token field and not an empty/undefined variable","Ensure the token is sent as a plain JSON string, not nested in an object or array","Update the passbolt browser extension/client to a version compatible with the JWT verify-token API"],"exampleFix":"// before\nconst res = await fetch('/jwt/verify.json', {body: JSON.stringify({verify_token: localStorage.token})});\n// after\nif (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(localStorage.token ?? '')) {\n  throw new Error('verify token must be a UUID');\n}\nconst res = await fetch('/jwt/verify.json', {body: JSON.stringify({verify_token: localStorage.token})});","handlingStrategy":"validation","validationCode":"const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\nif (typeof token !== 'string' || !UUID_RE.test(token)) throw new Error('verify token must be a UUID string');","typeGuard":"function isUuid(v: unknown): v is string {\n  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);\n}","tryCatchPattern":"try { await api.verifyToken(token, userId); } catch (e) { if (e.response?.status === 400) promptUserToRestartSetup(); else throw e; }","preventionTips":["Store and pass tokens as plain strings, never JSON-encode twice","Validate token shape client-side before any network call","Do not trim/transform tokens when reading from URL or storage","Use server-issued token values verbatim"],"tags":["jwt","uuid","validation","passbolt"],"backgroundTag":"invalid-argument-format","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"}