{"record":{"id":"a92aeac57f610d75","repo":"passbolt/passbolt_api","slug":"the-jwt-public-key-could-not-be-read-or-is-not-valid","errorCode":null,"errorMessage":"The JWT public key could not be read or is not valid.","messagePattern":"The JWT public key could not be read or is not valid\\.","errorType":"http","errorClass":"InvalidJwtKeyPairException","httpStatus":500,"severity":"error","filePath":"plugins/PassboltCe/JwtAuthentication/src/Service/AccessToken/JwtKeyPairService.php","lineNumber":117,"sourceCode":"            throw new InvalidJwtKeyPairException($e->getMessage());\n        }\n    }\n\n    /**\n     * Validate the key pair validity as defined by the public and secret services.\n     *\n     * @param string|null $uuid Uuid for testing aim\n     * @return object\n     * @throws \\Passbolt\\JwtAuthentication\\Error\\Exception\\AccessToken\\InvalidJwtKeyPairException\n     */\n    public function validateKeyPair(?string $uuid = null): object\n    {\n        // Minimal size of the private key\n        $minSecretKeySize = JwtTokenCreateService::JWT_KEY_LENGTH;\n        $uuid = $uuid ?? UuidFactory::uuid();\n        try {\n            if (!is_readable($this->publicService->getKeyPath())) {\n                throw new Exception(__('The JWT public key could not be read or is not valid.'));\n            }\n            $publicKey = file_get_contents($this->publicService->getKeyPath());\n            $secretKeySize = $this->publicService->getSecretKeySize();\n\n            if ($secretKeySize === 0) {\n                throw new Exception(__('The JWT public key could not be read or is not valid.'));\n            }\n\n            if ($secretKeySize < $minSecretKeySize) {\n                throw new Exception(__(\n                    'The JWT private key should be at least {0} bytes long.',\n                    $this->secretService::JWT_KEY_LENGTH\n                ));\n            }\n\n            $jwt = $this->secretService->createToken($uuid, '2 seconds');\n\n            return JWT::decode($jwt, new Key($publicKey, $this->secretService::JWT_ALG));","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltCe/JwtAuthentication/src/Service/AccessToken/JwtKeyPairService.php#L99-L135","documentation":"validateKeyPair() first checks is_readable() on the JWT public key path; if unreadable it throws this message. It also throws the identical message when getSecretKeySize() returns 0, i.e. the private key could not be read/parsed either. Both mean the installed JWT key pair files are missing, unreadable, or corrupt.","triggerScenarios":"validateKeyPair() is called (via execute) and either config/jwt/jwt.public.key is not readable by the current user, or its content/secret key size is 0 (empty or unparseable key files).","commonSituations":"JWT keys never generated (`passbolt create jwt_keys` skipped after install/upgrade); files lost during deployment because config/jwt was not persisted; empty files from a partially failed generation; wrong user permissions after container restart.","solutions":["Generate the key pair: sudo -u www-data bin/cake passbolt create jwt_keys (or the pro equivalent)","Verify both files exist and are non-empty: ls -la config/jwt/; head -1 config/jwt/jwt.public.key","Fix permissions so the runtime user can read them: chown www-data:www-data config/jwt/*; chmod 640 config/jwt/*","If files are empty/corrupt, delete them and regenerate the pair"],"exampleFix":"// before\n# empty jwt.public.key after failed generation\n// after\nrm config/jwt/jwt.public.key config/jwt/jwt.private.key\nsudo -u www-data bin/cake passbolt create jwt_keys","handlingStrategy":"validation","validationCode":"$pub = Configure::read('passbolt.jwt.publicKeyPath') ?? CONFIG . 'jwt' . DS . 'jwt.public.key';\nif (!is_readable($pub) || filesize($pub) === 0) { // regenerate key pair before calling validateKeyPair\n}","typeGuard":"if (!is_string($pub) || !is_file($pub) || !is_readable($pub)) { /* trigger regeneration */ }","tryCatchPattern":"try { $service->validateKeyPair(); } catch (InvalidJwtKeyPairException $e) { // run bin/cake passbolt create jwt_keys as runtime user }","preventionTips":["Run `passbolt create jwt_keys` after every install/upgrade","Persist config/jwt across deployments (volume/backup)","Include JWT key readability in health checks"],"tags":["jwt","file-read","validation","permissions"],"backgroundTag":"file-read-failed","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"}