{"record":{"id":"f877345e46f1f340","repo":"passbolt/passbolt_api","slug":"the-server-verify-token-is-missing-or-invalid","errorCode":null,"errorMessage":"The server verify token is missing or invalid.","messagePattern":"The server verify token is missing or invalid\\.","errorType":"http","errorClass":"BadRequestException","httpStatus":400,"severity":"warning","filePath":"src/Authenticator/GpgAuthenticatorTrait.php","lineNumber":38,"sourceCode":"use Cake\\Http\\Exception\\BadRequestException;\n\ntrait GpgAuthenticatorTrait\n{\n    /**\n     * @param \\App\\Utility\\OpenPGP\\OpenPGPBackendInterface|null $gpg GPG instance\n     * @param mixed $gpgMessage GPG message\n     * @param string $errorMessage Error message to throw if GPG message is not valid\n     * @throws \\Cake\\Http\\Exception\\BadRequestException If GPG message is not valid\n     * @return void\n     */\n    public function assertGpgMessageIsValid(?OpenPGPBackendInterface $gpg, mixed $gpgMessage, string $errorMessage): void // phpcs:ignore\n    {\n        if (\n            !isset($gpgMessage) ||\n            !is_string($gpgMessage) ||\n            !$gpg->isValidMessage($gpgMessage)\n        ) {\n            throw new BadRequestException($errorMessage);\n        }\n    }\n}\n","sourceCodeStart":20,"sourceCodeEnd":42,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/src/Authenticator/GpgAuthenticatorTrait.php#L20-L42","documentation":"Thrown by GpgAuthenticatorTrait::assertGpgMessageIsValid(), a generic guard that raises BadRequestException (HTTP 400) with the caller-supplied message when the GPG message is absent, not a string, or fails OpenPGPBackend::isValidMessage(). For this specific message the caller is GpgAuthenticator around line 200, where the decrypted server verify token from the client must be present and cryptographically valid during GPGAuth stage2 (token verification).","triggerScenarios":"GPGAuth stage2 request where the client posts a token/verify payload that is missing (null), is not a string (e.g. JSON-decoded object), or is an armored message the backend cannot validate (tampered, truncated, encrypted to the wrong key, or not signed correctly).","commonSituations":"Client sending an empty or malformed token field in the stage2 request body; man-in-the-middle or replay attempts with altered tokens; client and server key versions mismatched so decryption produces garbage; custom scripts/integrations posting raw JSON instead of the armored message; buggy proxy stripping the payload field.","solutions":["Check the stage2 request payload: the token field must be a non-empty string containing a valid armored GPG message.","Re-run the GPGAuth flow from stage0 with a compliant client (passbolt CLI/extension) instead of hand-crafted requests.","Verify the client encrypted the token to the correct server key (same fingerprint as passbolt.gpg.serverKey.fingerprint) and that the message was not modified in transit.","If validating input server-side in custom code, call assertGpgMessageIsValid() early so the failure surfaces as a 400 with a clear message."],"exampleFix":"// before: sending a raw JSON token\n{\"token\": {\"data\": \"abc\"}}\n\n// after: send the armored GPG message string\n{\"token\": \"-----BEGIN PGP MESSAGE-----\\n...\\n-----END PGP MESSAGE-----\"}","handlingStrategy":"type-guard","validationCode":"$token = $request->getData('token') ?? $request->getData('gpg_auth.token');\nif (!is_string($token) || $token === '' || !str_contains($token, 'BEGIN PGP MESSAGE')) {\n    // reject before calling assertGpgMessageIsValid\n}","typeGuard":"function isArmoredMessage(mixed $msg): bool {\n    return is_string($msg)\n        && str_contains($msg, '-----BEGIN PGP MESSAGE-----');\n}","tryCatchPattern":"try {\n    $this->assertGpgMessageIsValid($gpg, $token, __('The server verify token is missing or invalid.'));\n} catch (BadRequestException $e) {\n    return $this->error(400, $e->getMessage());\n}","preventionTips":["Use a maintained passbolt client (CLI/extension) rather than hand-crafted stage2 requests.","Always send the token as a single armored string field; never pre-parse it into JSON objects.","Ensure TLS/proxies do not truncate large POST bodies containing armored messages.","Log the failing request payload shape (not content) to spot malformed integrations early."],"tags":["gnupg","bad-request","token-validation","gpgauth","client-input"],"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"}