spring-projects/spring-security · error · Saml2Exception
Metadata response is missing a SingleSignOnService, necessar
Error message
Metadata response is missing a SingleSignOnService, necessary for sending AuthnRequests
What it means
Spring Security SAML2 throws this Saml2Exception when the parsed IdP metadata has an IDPSSODescriptor but no SingleSignOnService entries. The SingleSignOnService location/binding is what the application uses to send AuthnRequest messages; without it the RelyingPartyRegistration cannot be constructed.
Source
Thrown at saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/registration/OpenSamlAssertingPartyDetails.java:130
if (verification.isEmpty()) {
throw new Saml2Exception(
"Metadata response is missing verification certificates, necessary for verifying SAML assertions");
}
String entityId = entity.getEntityID();
Assert.notNull(entityId, "EntityDescriptor#EntityID cannot be null");
OpenSamlAssertingPartyDetails.Builder builder = new OpenSamlAssertingPartyDetails.Builder(entity)
.entityId(entityId)
.wantAuthnRequestsSigned(Boolean.TRUE.equals(idpssoDescriptor.getWantAuthnRequestsSigned()))
.verificationX509Credentials((c) -> c.addAll(verification))
.encryptionX509Credentials((c) -> c.addAll(encryption));
List<SigningMethod> signingMethods = signingMethods(idpssoDescriptor);
for (SigningMethod method : signingMethods) {
Assert.notNull(method.getAlgorithm(), "EntityDescriptor declares a SigningMethod with no value");
builder.signingAlgorithms((algorithms) -> algorithms.add(method.getAlgorithm()));
}
if (idpssoDescriptor.getSingleSignOnServices().isEmpty()) {
throw new Saml2Exception(
"Metadata response is missing a SingleSignOnService, necessary for sending AuthnRequests");
}
for (SingleSignOnService singleSignOnService : idpssoDescriptor.getSingleSignOnServices()) {
Saml2MessageBinding binding;
if (Saml2MessageBinding.POST.getUrn().equals(singleSignOnService.getBinding())) {
binding = Saml2MessageBinding.POST;
}
else if (Saml2MessageBinding.REDIRECT.getUrn().equals(singleSignOnService.getBinding())) {
binding = Saml2MessageBinding.REDIRECT;
}
else {
continue;
}
String location = singleSignOnService.getLocation();
Assert.notNull(location, "EntityDescriptor has a SingleSignOnService declaration, but no Location");
builder.singleSignOnServiceLocation(location).singleSignOnServiceBinding(binding);
break;
}View on GitHub (pinned to 96852e8860)
Solutions
- Use the IdP's official metadata URL/file that includes <md:SingleSignOnService Binding="...urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="..."/> and re-import
- Manually set it via assertingParty(details -> details.singleSignOnServiceLocation("https://idp/sso").singleSignOnServiceBinding(Saml2MessageBinding.POST))
- Confirm the metadata document is IdP metadata (IDPSSODescriptor), not SP metadata
- If metadata is generated, fix the generator to emit at least one SingleSignOnService
Example fix
// before (metadata lacks SSO service -> error)
RelyingPartyRegistration r = RelyingPartyRegistrations.fromMetadataLocation("https://idp/meta").build();
// after: declare SSO service manually
RelyingPartyRegistration r = RelyingPartyRegistration.withAssertingPartyMetadata(party -> party
.entityId("https://idp.example.com/sso")
.singleSignOnServiceLocation("https://idp.example.com/sso/SSO")
.singleSignOnServiceBinding(Saml2MessageBinding.POST))
.registrationId("idp")
.build(); Defensive patterns
Strategy: validation
Validate before calling
Document doc = parseXml(metadataBytes);
NodeList sso = doc.getElementsByTagNameNS("urn:oasis:names:tc:SAML:2.0:metadata", "SingleSignOnService");
if (sso.getLength() == 0) throw new IllegalArgumentException("Metadata has no SingleSignOnService"); Try / catch
try {
return RelyingPartyRegistrations.fromMetadataLocation(location).build();
} catch (Saml2Exception ex) {
// supply SSO location manually from IdP admin console values
return builderWithManualSsoEndpoint(ex);
} Prevention
- Never hand-write metadata without a SingleSignOnService element; prefer the IdP's published metadata
- Check that the URL you import is IdP metadata, not SP metadata
- Assert at startup (fail fast) that every registration resolves an SSO location
When it happens
Trigger: RelyingPartyRegistrations.fromMetadata/fromMetadataLocation or OpenSamlAssertingPartyDetails.withEntityDescriptor on metadata where idpssoDescriptor.getSingleSignOnServices() is empty.
Common situations: Hand-crafted metadata containing only certificates and entityId; IdP published metadata limited to SLO/logout services; truncated or partially downloaded metadata; wrong entity (e.g. SP metadata fed as IdP metadata).
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- Metadata response is missing verification certificates, nece
- Unsupported element type:
- Metadata response is missing the necessary IDPSSODescriptor
- registration not found
- invalid_destination
AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10).
Data as JSON: /api/errors/cd4f955437919537.
Report an issue: GitHub.