apereo/cas · warning

Secret key for signing is not defined for

Error message

Secret key for signing is not defined for [{}]. CAS will attempt to auto-generate the signing key

What it means

Warning from BaseStringCipherExecutor.configureSigningParameters when the signing key for a string-based cipher executor (cookies, webflow state, etc.) is blank. CAS generates a JSON Web Key of the configured signingKeySize and prints a warning containing the property to persist.

Solutions

  1. Generate a signing JWK and set the property named in getSigningKeySetting() (printed in the follow-up warning line).
  2. Persist the key so restarts do not regenerate it and invalidate signed values.
  3. Use the same signing key on every CAS node in the deployment.
  4. If signing is unnecessary, disable it explicitly rather than leaving the key blank.

Example fix

// before
cas.webflow.crypto.signing.enabled=true
// after
cas.webflow.crypto.signing.enabled=true
cas.webflow.crypto.signing.key=eyJvY3R...generated-jwk...
Defensive patterns

Strategy: validation

Validate before calling

String signingKey = webflowCrypto.getSigning().getKey();
if (signingKey == null || signingKey.isBlank()) {
    throw new IllegalStateException("Webflow signing key not configured; generate and persist a JWK");
}

Prevention

When it happens

Trigger: Starting CAS with a string cipher executor enabled but its signing key property unset; the executor name appears in the message (e.g. 'CAS Cookie Encryption').

Common situations: Enabling encrypted/signed cookies or webflow crypto without generating keys; upgraded CAS versions where signing became mandatory and legacy configs lack the key; cluster nodes drifting apart with per-node generated keys.

Understand the failure class

Background: "missing required config value" errors: why libraries refuse to start when a configuration key is empty, unset, or blank — this error's family across 48 libraries.

Related errors


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

Appendix: source

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

    }


    protected String encryptValueAsJwt(final Key encryptionKey, final Serializable value) {
        val headers = new LinkedHashMap<>(getCommonHeaders());
        headers.putAll(getEncryptionOpHeaders());
        return JsonWebTokenEncryptor.builder()
            .key(encryptionKey)
            .algorithm(encryptionAlgorithm)
            .encryptionMethod(contentEncryptionAlgorithmIdentifier)
            .headers(headers)
            .build()
            .encrypt(value);
    }

    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());

View on GitHub (pinned to e7288fc434)