apereo/cas · error · RuntimeException

Provided signing key as a JSON web key does not carry a…

Error message

Provided signing key as a JSON web key does not carry a private key

What it means

During signing-key configuration, the provided signing secret parsed as a JSON web key (JWK), but that JWK carries no private key material. Signing requires the private key, so configuration aborts with RuntimeException. The input at fault is the signing key property: a public-only JWK was supplied where a private/public JWK pair is required.

Solutions

  1. Provide a JWK that includes the private key ('d' parameter) for signing
  2. Generate a fresh key pair via CAS key-generation endpoints or jose tooling and store the full JWK
  3. If only signing/verification is intended, configure the key so the public-key path is used instead
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at core/cas-server-core-util-api/src/main/java/org/apereo/cas/util/cipher/BaseStringCipherExecutor.java:203 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08). Data as JSON: /api/errors/e4ec05346050c465. Report an issue: GitHub.

Appendix: source

Thrown at core/cas-server-core-util-api/src/main/java/org/apereo/cas/util/cipher/BaseStringCipherExecutor.java:203

    private void configureSigningParameters(final String secretKeySigning) {
        var signingKeyToUse = secretKeySigning;
        if (StringUtils.isBlank(signingKeyToUse)) {
            LOGGER.warn("Secret key for signing is not defined for [{}]. CAS will attempt to auto-generate the signing key", getName());
            signingKeyToUse = EncodingUtils.generateJsonWebKey(this.signingKeySize);
            val prop = String.format("%s=%s", getSigningKeySetting(), signingKeyToUse);
            //CHECKSTYLE:OFF
            LOGGER.warn("Generated signing key [{}] of size [{}] for [{}]. The generated key MUST be added to CAS settings:\n\n\t{}\n\n",
                signingKeyToUse, this.signingKeySize, getName(), prop);
            //CHECKSTYLE:ON
        } else {
            try {
                val jwk = (PublicJsonWebKey) EncodingUtils.newJsonWebKey(signingKeyToUse);
                LOGGER.trace("Parsed signing key as a JSON web key for [{}] with kid [{}]", getName(), jwk.getKeyId());
                if (jwk.getPrivateKey() == null) {
                    val msg = "Provided signing key as a JSON web key does not carry a private key";
                    LOGGER.error(msg);
                    throw new RuntimeException(msg);
                }
                setSigningKey(jwk.getPrivateKey());
            } catch (final Exception e) {
                LOGGER.trace("Unable to recognize signing key for [{}] as a JSON web key: [{}].", getSigningKeySetting(), e.getMessage());
                LOGGER.debug("Using pre-defined signing key to use for [{}]", getSigningKeySetting());
            }
        }
        configureSigningKey(signingKeyToUse);
    }

    private void configureEncryptionParameters(final String secretKeyEncryption, final String contentEncryptionAlgorithmIdentifier) {
        var secretKeyToUse = secretKeyEncryption;
        if (StringUtils.isBlank(secretKeyToUse)) {
            LOGGER.warn("Secret key for encryption is not defined for [{}]; CAS will attempt to auto-generate the encryption key", getName());
            secretKeyToUse = EncodingUtils.generateJsonWebKey(this.encryptionKeySize);
            val prop = String.format("%s=%s", getEncryptionKeySetting(), secretKeyToUse);
            //CHECKSTYLE:OFF
            LOGGER.warn("Generated encryption key [{}] of size [{}] for [{}]. The generated key MUST be added to CAS settings:\n\n\t{}\n\n",

View on GitHub (pinned to e7288fc434)