{"record":{"id":"a62351f18ade2f24","repo":"spring-projects/spring-security","slug":"decryption-error","errorCode":"decryption_error","errorMessage":"decryptionError(ex.getMessage())","messagePattern":"decryptionError\\(ex\\.getMessage\\(\\)\\)","errorType":"error_code","errorClass":"Saml2AuthenticationException","httpStatus":null,"severity":"error","filePath":"saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/BaseOpenSamlAuthenticationProvider.java","lineNumber":429,"sourceCode":"\t\t\t\tCollection<Saml2X509Credential> credentials = details.getVerificationX509Credentials();\n\t\t\t\tCollection<Saml2Error> errors = this.saml.withVerificationKeys(credentials)\n\t\t\t\t\t.entityId(details.getEntityId())\n\t\t\t\t\t.verify(response);\n\t\t\t\treturn Saml2ResponseValidatorResult.failure(errors);\n\t\t\t}\n\t\t\treturn Saml2ResponseValidatorResult.success();\n\t\t};\n\t}\n\n\tprivate Consumer<ResponseToken> createDefaultResponseElementsDecrypter() {\n\t\treturn (responseToken) -> {\n\t\t\tResponse response = responseToken.getResponse();\n\t\t\tRelyingPartyRegistration registration = responseToken.getToken().getRelyingPartyRegistration();\n\t\t\ttry {\n\t\t\t\tthis.saml.withDecryptionKeys(registration.getDecryptionX509Credentials()).decrypt(response);\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tthrow new Saml2AuthenticationException(Saml2Error.decryptionError(ex.getMessage()), ex);\n\t\t\t}\n\t\t};\n\t}\n\n\tprivate Converter<AssertionToken, Saml2ResponseValidatorResult> createDefaultAssertionSignatureValidator() {\n\t\treturn (assertionToken) -> {\n\t\t\tRelyingPartyRegistration registration = assertionToken.getToken().getRelyingPartyRegistration();\n\t\t\tAssertion assertion = assertionToken.getAssertion();\n\t\t\tif (assertion.isSigned()) {\n\t\t\t\tAssertingPartyMetadata details = registration.getAssertingPartyMetadata();\n\t\t\t\tCollection<Saml2X509Credential> credentials = details.getVerificationX509Credentials();\n\t\t\t\tCollection<Saml2Error> errors = this.saml.withVerificationKeys(credentials)\n\t\t\t\t\t.entityId(details.getEntityId())\n\t\t\t\t\t.verify(assertion);\n\t\t\t\treturn Saml2ResponseValidatorResult.failure(errors);\n\t\t\t}\n\t\t\treturn Saml2ResponseValidatorResult.success();\n\t\t};","sourceCodeStart":411,"sourceCodeEnd":447,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/BaseOpenSamlAuthenticationProvider.java#L411-L447","documentation":"The default response elements decrypter throws decryption_error when SAML response decryption with the configured decryption keys fails. Encrypted assertions/NameIDs cannot be decrypted, typically because the SP lacks the correct private key corresponding to the certificate the IdP used for encryption.","triggerScenarios":"The IdP encrypts assertions (or the EncryptedID) and this.saml.withDecryptionKeys(...).decrypt(response) fails — no matching private key in registration.getDecryptionX509Credentials(), wrong key format, corrupted XML encryption elements, or unsupported encryption algorithm.","commonSituations":"After rotating certificates the old decryption key was removed before the IdP switched; keystore only holds the signing key, not the encryption key; PEM/PKCS12 conversion issues producing an unusable private key; IdP switched to an encryption algorithm OpenSAML is not configured for.","solutions":["Add the private key whose certificate the IdP uses for encryption to the RelyingPartyRegistration's decryption credentials","During key rotation, keep the old decryption key alongside the new one until the IdP has switched","Verify the private key loads correctly (correct format/password) by decrypting a sample payload in a test","Align encryption algorithms between IdP and SP, or upgrade OpenSAML/Spring Security for newer algorithm support"],"exampleFix":"// before\n.registrationId(\"idp\")\n.signingX509Credentials((c) -> c.add(signingCert)) // only signing key\n// after\n.decryptionX509Credentials((c) -> c.add(new RsaKeyConverter()\n    .setPrivateKey(privateKeyPem).getX509Credential()))\n.signingX509Credentials((c) -> c.add(signingCert))","handlingStrategy":"validation","validationCode":"// Verify the decryption key can be loaded and pairs with the IdP encryption cert\nX509Certificate idpEncryptionCert = fetchFromMetadata(idpMetadataUrl);\nX509Certificate spCert = loadSpCertificate(spPrivateKey);\nif (!idpEncryptionCert.equals(spCert)) {\n    throw new IllegalStateException(\n        \"SP decryption cert does not match the IdP's encryption certificate\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    Authentication result = provider.authenticate(token);\n} catch (Saml2AuthenticationException e) {\n    if (Saml2ErrorCodes.DECRYPTION_ERROR.equals(e.getError().getErrorCode())) {\n        logger.error(\"SAML decryption failed — check decryption keys\", e.getCause());\n        throw e;\n    }\n}","preventionTips":["Configure decryptionX509Credentials explicitly, not just signing credentials","During certificate rotation keep old + new decryption keys until the IdP switches","Verify private key files decrypt correctly (format, password) before deployment","Compare your SP certificate against the IdP metadata encryption certificate regularly"],"tags":["saml2","spring-security","decryption","keystore"],"backgroundTag":"saml-decryption-failed","analyzedSha":"96852e8860138a482cb13d1479573f24ff6443c6","analyzedAt":"2026-09-10T23:25:23.477Z","contentChangedAt":"2026-09-10T23:25:23.477Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}