{"record":{"id":"c335c931ab5d238c","repo":"passbolt/passbolt_api","slug":"the-permission-of-publickeypath-could-not-be-set-to","errorCode":null,"errorMessage":"The permission of $publicKeyPath could not be set to $permission.","messagePattern":"The permission of \\$publicKeyPath could not be set to \\$permission\\.","errorType":"http","errorClass":"InvalidJwtKeyPairException","httpStatus":500,"severity":"error","filePath":"plugins/PassboltCe/JwtAuthentication/src/Service/AccessToken/JwtKeyPairService.php","lineNumber":96,"sourceCode":"                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.\");\n            }\n        } catch (Throwable $e) {\n            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();","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltCe/JwtAuthentication/src/Service/AccessToken/JwtKeyPairService.php#L78-L114","documentation":"Same as the private-key variant: createKeyPair() chmods the public key file to 0640 and throws this error naming the public key path when chmod() fails. It is rethrown as InvalidJwtKeyPairException, aborting key pair creation.","triggerScenarios":"chmod($publicKeyPath, 0640) returns false after the private key chmod succeeded — ownership mismatch between the writing process and the file, unsupported filesystem, or PHP security restrictions on the path.","commonSituations":"Mixed ownership in config/jwt (some files root-owned, some www-data-owned) from previous partial runs; root_squash on NFS; OpenCart-style shared hosting where the web user cannot chmod CLI-created files.","solutions":["Normalise ownership of the whole directory: chown -R www-data:www-data config/jwt then re-run the command","Manually chmod 640 config/jwt/jwt.public.key and re-run validation","Delete partial key files and regenerate as the runtime user: rm config/jwt/* && sudo -u www-data bin/cake passbolt create jwt_keys","Confirm the filesystem honours chmod (touch f; chmod 600 f; stat f)"],"exampleFix":"// before\n# partial run left root-owned files\n// after\nsudo chown -R www-data:www-data config/jwt\nsudo rm config/jwt/*\nsudo -u www-data bin/cake passbolt create jwt_keys","handlingStrategy":"try-catch","validationCode":"clearstatcache();\n$owner = fileowner($publicKeyPath);\nif ($owner !== posix_getuid() && !posix_getpwuid($owner)) { /* ownership anomaly */ }","typeGuard":null,"tryCatchPattern":"try { $service->createKeyPair(); } catch (InvalidJwtKeyPairException $e) { // chown -R www-data:www-data config/jwt and regenerate cleanly }","preventionTips":["Delete partial key files before regenerating (rm config/jwt/*)","Keep single ownership across config/jwt","Pre-set permissions at build time on filesystems without chmod support"],"tags":["jwt","permissions","chmod","file"],"backgroundTag":"permission-denied","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"}