apereo/cas · warning
Secret key for encryption is undefined under
Error message
Secret key for encryption is undefined under [{}]. CAS will attempt to auto-generate the encryption key What it means
Warning logged by BaseBinaryCipherExecutor.ensureEncryptionKeyExists when the configured encryption secret key setting is blank. CAS then auto-generates a random key at runtime and warns that the key MUST be added to configuration; without persisting it, keys are regenerated on each restart.
Solutions
- Generate a Base64 key of the required size (e.g. via CasConfigurationUtils/KeyGenerator or 'java -jar cas-server* --generate-key') and set it in the corresponding cas.*.encryption.key property.
- Copy the generated key from the warning log line into application.properties/yml so it persists across restarts.
- If crypto is not needed, disable the cipher executor feature rather than leaving the key blank.
Example fix
// before (application.properties) cas.ticket.crypto.enabled=true // after cas.ticket.crypto.enabled=true cas.ticket.crypto.encryption.key=ZXhhbXBsZS1iYXNlNjQtZW5jb2RlZC1rZXktMTI4LWJpdHM=
Defensive patterns
Strategy: validation
Validate before calling
String key = casProperties.getTicket().getCrypto().getEncryption().getKey();
if (key == null || key.isBlank()) {
throw new IllegalStateException("Encryption key must be set in cas.ticket.crypto.encryption.key before startup");
} Prevention
- Run CAS keygen and commit generated keys to config/secrets before first deployment.
- Add a startup smoke check that all enabled crypto features have non-blank keys.
- Keep keys in a vault injected via environment, not generated ad hoc.
When it happens
Trigger: Starting CAS with a cipher executor (tickets, OAuth/OIDC tokens, webflow crypto, etc.) whose cas.* encryption key property (e.g. cas.ticket.crypto.encryption.key) is unset or empty.
Common situations: Fresh CAS install with crypto enabled but keys not generated yet; keys lost after switching deployments; enabling per-service or per-feature crypto without running the documented keygen step.
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
- Unable to use 'none' as introspection encryption algorithm
- Unable to use 'none' as user-info encryption algorithm
- Service with client id is configured to encrypt tokens, yet…
- Unable to use 'none' as ID token encryption algorithm
- Unable to encrypt assertion for
AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08).
Data as JSON: /api/errors/8eca169cd50e9c5e.
Report an issue: GitHub.
Appendix: source
Thrown at core/cas-server-core-util-api/src/main/java/org/apereo/cas/util/cipher/BaseBinaryCipherExecutor.java:163
private byte[] decodeWithPrefixedInitializationVector(final byte[] value) throws Exception {
val iv = Arrays.copyOfRange(value, 0, GCM_IV_LENGTH);
val encrypted = Arrays.copyOfRange(value, GCM_IV_LENGTH, value.length);
val aesCipher = Cipher.getInstance(CIPHER_ALGORITHM);
aesCipher.init(Cipher.DECRYPT_MODE, this.encryptionKey, new GCMParameterSpec(GCM_TAG_LENGTH, iv));
return aesCipher.doFinal(encrypted);
}
private byte[] decodeWithLegacyParameterSpec(final byte[] value) throws Exception {
val aesCipher = Cipher.getInstance(CIPHER_ALGORITHM);
aesCipher.init(Cipher.DECRYPT_MODE, this.encryptionKey, this.parameterSpec);
return aesCipher.doFinal(value);
}
private void ensureEncryptionKeyExists(final String encryptionSecretKey, final int encryptionKeySize) {
final byte[] genEncryptionKey;
if (StringUtils.isBlank(encryptionSecretKey)) {
LOGGER.warn("Secret key for encryption is undefined under [{}]. CAS will attempt to auto-generate the encryption key", getEncryptionKeySetting());
if (encryptionKeySize <= MINIMUM_ENCRYPTION_KEY_LENGTH) {
val key = new Base64RandomStringGenerator(encryptionKeySize).getNewString();
val prop = String.format("%s=%s", getEncryptionKeySetting(), key);
issueWarningToAddKeyToSettings("encryption", encryptionKeySize, key, prop);
genEncryptionKey = EncodingUtils.decodeBase64(key);
} else {
val keyGenerator = FunctionUtils.doUnchecked(() -> KeyGenerator.getInstance(this.secretKeyAlgorithm));
keyGenerator.init(encryptionKeySize);
val secretKey = keyGenerator.generateKey();
genEncryptionKey = secretKey.getEncoded();
val encodedKey = EncodingUtils.encodeBase64(genEncryptionKey);
val prop = String.format("%s=%s", getEncryptionKeySetting(), encodedKey);
issueWarningToAddKeyToSettings("encryption", encryptionKeySize, encodedKey, prop);
}
} else if (encryptionKeySize <= MINIMUM_ENCRYPTION_KEY_LENGTH) {
val base64 = EncodingUtils.isBase64(encryptionSecretKey);
val key = base64 ? EncodingUtils.decodeBase64(encryptionSecretKey) : ArrayUtils.EMPTY_BYTE_ARRAY;View on GitHub (pinned to e7288fc434)