{"record":{"id":"0dfee4c227684672","repo":"passbolt/passbolt_api","slug":"the-jwt-private-key-could-not-be-written","errorCode":null,"errorMessage":"The JWT private key could not be written.","messagePattern":"The JWT private key could not be written\\.","errorType":"http","errorClass":"InvalidJwtKeyPairException","httpStatus":500,"severity":"error","filePath":"plugins/PassboltCe/JwtAuthentication/src/Service/AccessToken/JwtKeyPairService.php","lineNumber":78,"sourceCode":"            return;\n        }\n\n        $config = [\n            'digest_alg' => JwtTokenCreateService::JWT_ALG,\n            'private_key_bits' => $this->getKeyLength(),\n            'private_key_type' => OPENSSL_KEYTYPE_RSA,\n        ];\n        $secretKeyPath = $this->getSecretKeyPath();\n        $publicKeyPath = $this->getPublicKeyPath();\n\n        try {\n            $pk = openssl_pkey_new($config);\n            if ($pk === false) {\n                throw new Exception('The JWT private key could not be created.');\n            }\n            $export = openssl_pkey_export_to_file($pk, $secretKeyPath);\n            if ($export === false) {\n                throw new Exception('The JWT private key could not be written.');\n            }\n            $publicKey = openssl_pkey_get_details($pk)['key'] ?? false;\n            if ($publicKey === false) {\n                throw new Exception('The JWT public key could not be extracted.');\n            }\n            $export = file_put_contents($publicKeyPath, $publicKey);\n            if ($export === false) {\n                throw new Exception('The JWT public key could not be written.');\n            }\n\n            $permission = 0640;\n            $res = chmod($secretKeyPath, $permission);\n            if (!$res) {\n                throw new Exception(\"The permission of $secretKeyPath could not be set to $permission.\");\n            }\n            $res = chmod($publicKeyPath, $permission);\n            if (!$res) {\n                throw new Exception(\"The permission of $publicKeyPath could not be set to $permission.\");","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltCe/JwtAuthentication/src/Service/AccessToken/JwtKeyPairService.php#L60-L96","documentation":"After openssl_pkey_new succeeds, createKeyPair() exports the private key to the secret key path via openssl_pkey_export_to_file(). When that call returns false (export failure, usually a filesystem permission problem on the target directory), this error is thrown and rethrown as InvalidJwtKeyPairException.","triggerScenarios":"openssl_pkey_export_to_file($pk, $secretKeyPath) returns false — the directory at getSecretKeyPath() (config/jwt/) does not exist, is not writable by the current user (e.g. www-data vs CLI user mismatch), or an OpenSSL passphrase/config issue blocks export.","commonSituations":"config/jwt/ not created before running the command; running `passbolt create jwt_keys` as root then the web server cannot continue; read-only or immutable mount; SELinux/AppArmor blocking writes.","solutions":["Create the JWT directory and give the web user ownership: mkdir -p config/jwt && chown www-data:www-data config/jwt","Check free disk space and that the path is on a writable mount (df -h; mount)","Verify no passphrase/openssl config error: capture openssl error with openssl_error_string() right after the failure","Re-run the key pair generation command as the user that owns config/jwt"],"exampleFix":"// before\n$export = openssl_pkey_export_to_file($pk, $secretKeyPath); // dir missing\n// after\nif (!is_dir(dirname($secretKeyPath))) {\n    mkdir(dirname($secretKeyPath), 0770, true);\n}\n$export = openssl_pkey_export_to_file($pk, $secretKeyPath);","handlingStrategy":"validation","validationCode":"$dir = dirname($secretKeyPath);\nif (!is_dir($dir) || !is_writable($dir)) { mkdir($dir, 0770, true); }","typeGuard":null,"tryCatchPattern":"try { $service->createKeyPair(); } catch (InvalidJwtKeyPairException $e) { // check is_writable(config/jwt) and current process user }","preventionTips":["Create config/jwt with correct ownership (www-data) at deploy time","Never run key generation as root without chown afterwards","Monitor disk space on the config volume"],"tags":["openssl","jwt","file-write","permissions"],"backgroundTag":"file-write-failed","analyzedSha":"31c1bbc10f32808a607fa9bd81891e898779c0bc","analyzedAt":"2026-09-17T00:04:38.960Z","contentChangedAt":"2026-09-17T00:04:38.960Z","schemaVersion":2},"datasetVersion":"2026-09-21T09:17:21.228Z"}