passbolt/passbolt_api · critical · InvalidJwtKeyPairException

The JWT public key could not be extracted.

Error message

The JWT public key could not be extracted.

What it means

Thrown by JwksGetService::getDetails when openssl_pkey_get_public() fails to parse the JWT public key file contents into a usable OpenSSL key resource. This signals the PEM file at the configured jwt key path is corrupt, empty, or not a valid public key.

Solutions

  1. Regenerate the JWT key pair: bin/cake passbolt create_jwt_keys
  2. Verify the PEM content: openssl pkey -pubin -in config/jwt/jwt.public.key -text -noout
  3. Check file permissions/readability for the web server user and that the file isn't empty
  4. If keys come from env/secret mount, confirm the secret contents are the full PEM, not base64 or truncated

Example fix

// regenerate
bin/cake passbolt create_jwt_keys
// verify
openssl pkey -pubin -in config/jwt/jwt.public.key -noout
Defensive patterns

Strategy: validation

Validate before calling

$pub = file_get_contents($path);
if (empty($pub) || openssl_pkey_get_public($pub) === false) {
    throw new RuntimeException('jwt.public.key invalid at ' . $path);
}

Try / catch

try { $jwks = $service->getPublicKey(); } catch (InvalidJwtKeyPairException $e) { regenerateKeys(); }

Prevention

When it happens

Trigger: Building the JWKS (getPublicKey/getSecretKeySize) when the jwt.public.key file contains garbage, an HTML error page, an encrypted key, or truncated content.

Common situations: Key pair generation failed or was interrupted; file overwritten during deployment; wrong file mounted (e.g. private key expected but public slot holds something else); copy/paste artifacts in the PEM.

Related errors


AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17). Data as JSON: /api/errors/384eb9a1af622329. Report an issue: GitHub.

Appendix: source

Thrown at plugins/PassboltCe/JwtAuthentication/src/Service/AccessToken/JwksGetService.php:64

     * @return int
     */
    public function getSecretKeySize(): int
    {
        $details = $this->getDetails();

        return $details['bits'] ?? 0;
    }

    /**
     * @return array
     * @throws \Passbolt\JwtAuthentication\Error\Exception\AccessToken\InvalidJwtKeyPairException if the public key file is not parsable.
     */
    private function getDetails(): array
    {
        $pubKey = $this->readKeyFileContent();
        $res = openssl_pkey_get_public($pubKey);
        if ($res === false) {
            throw new InvalidJwtKeyPairException(__('The JWT public key could not be extracted.'));
        }
        $details = openssl_pkey_get_details($res);
        if ($details === false) {
            throw new InvalidJwtKeyPairException(__('The JWT public key details could not be read.'));
        }

        return $details;
    }

    /**
     * @return string|false
     * @throws \Passbolt\JwtAuthentication\Error\Exception\AccessToken\InvalidJwtKeyPairException if the public key file is not found or not readable.
     */
    public function getRawPublicKey(): string|false
    {
        return $this->readKeyFileContent();
    }
}

View on GitHub (pinned to 31c1bbc10f)