passbolt/passbolt_api · error · InvalidJwtKeyPairException
The permission of $secretKeyPath could not be set to…
Error message
The permission of $secretKeyPath could not be set to $permission.
What it means
After writing both key files, createKeyPair() chmods the private key to 0640. If chmod() fails, this interpolated error names the failing secret key path and the intended permission, then is rethrown as InvalidJwtKeyPairException.
Solutions
- Run the key generation as the same user that owns config/jwt (e.g. su -s /bin/bash -c '...' www-data) or chown the files afterwards: chown www-data:www-data config/jwt/*
- Set the permissions manually: chmod 640 config/jwt/jwt.private.key config/jwt/jwt.public.key, then re-run validation only
- Check whether the filesystem supports chmod; on unsupported mounts pre-set permissions at mount/build time
- Verify open_basedir/safe-mode settings in php.ini are not restricting the path
Example fix
// before sudo bin/cake passbolt create jwt_keys # files owned by root // after sudo -u www-data bin/cake passbolt create jwt_keys sudo chmod 640 config/jwt/jwt.*.key
Defensive patterns
Strategy: try-catch
Validate before calling
clearstatcache();
if (fileowner($secretKeyPath) !== posix_getuid()) { /* regenerate as owning user or pre-chmod */ } Try / catch
try { $service->createKeyPair(); } catch (InvalidJwtKeyPairException $e) { exec('chmod 640 ' . escapeshellarg($secretKeyPath)); } Prevention
- Run key generation as the web server user (sudo -u www-data)
- Avoid root-created key files without follow-up chown
- Verify chmod support on the target filesystem (not NFS with root_squash)
When it happens
Trigger: chmod($secretKeyPath, 0640) returns false — the file is owned by another user (root created it, web server cannot chmod), the filesystem does not support chmod (some NFS/Samba mounts, Windows), or safe-mode/open_basedir restrictions apply.
Common situations: Running the JWT command with sudo then serving passbolt as www-data; NFS mounts with root_squash; containers running as a different UID than the key file owner.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- The permission of $publicKeyPath could not be set to…
- The JWT private key could not be written.
- The JWT public key could not be read or is not valid.
- The JWT public key could not be written.
- The key pair for JWT Authentication is not complete.
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/d816d13672c70012.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/PassboltCe/JwtAuthentication/src/Service/AccessToken/JwtKeyPairService.php:92
throw new Exception('The JWT private key could not be created.');
}
$export = openssl_pkey_export_to_file($pk, $secretKeyPath);
if ($export === false) {
throw new Exception('The JWT private key could not be written.');
}
$publicKey = openssl_pkey_get_details($pk)['key'] ?? false;
if ($publicKey === false) {
throw new Exception('The JWT public key could not be extracted.');
}
$export = file_put_contents($publicKeyPath, $publicKey);
if ($export === false) {
throw new Exception('The JWT public key could not be written.');
}
$permission = 0640;
$res = chmod($secretKeyPath, $permission);
if (!$res) {
throw new Exception("The permission of $secretKeyPath could not be set to $permission.");
}
$res = chmod($publicKeyPath, $permission);
if (!$res) {
throw new Exception("The permission of $publicKeyPath could not be set to $permission.");
}
} catch (Throwable $e) {
throw new InvalidJwtKeyPairException($e->getMessage());
}
}
/**
* Validate the key pair validity as defined by the public and secret services.
*
* @param string|null $uuid Uuid for testing aim
* @return object
* @throws \Passbolt\JwtAuthentication\Error\Exception\AccessToken\InvalidJwtKeyPairException
*/
public function validateKeyPair(?string $uuid = null): objectView on GitHub (pinned to 31c1bbc10f)