spring-projects/spring-security · error · Saml2AuthenticationException

relying_party_registration_not_found

relying_party_registration_not_found

Error message

registration not found

What it means

Saml2LogoutRequestFilter resolves the RelyingPartyRegistration for the registrationId extracted from the logout request (via the Resolver resolve step). When the registration resolver returns null — i.e. no registered relying party matches the request's registration id — the filter throws a Saml2AuthenticationException with the relyingPartyRegistrationNotFound error. Spring Security cannot build the logout flow without knowing the entity IDs, keys, and SLO endpoints associated with the registration.

Source

Thrown at saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/Saml2LogoutRequestFilter.java:268

			this.relyingPartyRegistrationResolver = relyingPartyRegistrationResolver;
		}

		@Override
		public @Nullable Saml2LogoutRequestValidatorParameters resolve(HttpServletRequest request,
				@Nullable Authentication authentication) {
			String serialized = request.getParameter(Saml2ParameterNames.SAML_REQUEST);
			if (serialized == null) {
				return null;
			}
			RequestMatcher.MatchResult result = this.logoutRequestMatcher.matcher(request);
			if (!result.isMatch()) {
				return null;
			}
			String registrationId = getRegistrationId(result, authentication);
			RelyingPartyRegistration registration = this.relyingPartyRegistrationResolver.resolve(request,
					registrationId);
			if (registration == null) {
				throw new Saml2AuthenticationException(
						Saml2Error.relyingPartyRegistrationNotFound("registration not found"));
			}
			UriResolver uriResolver = RelyingPartyRegistrationPlaceholderResolvers.uriResolver(request, registration);
			String entityId = uriResolver.resolve(registration.getEntityId());
			entityId = Objects.requireNonNull(entityId);
			String logoutLocation = uriResolver.resolve(registration.getSingleLogoutServiceLocation());
			String logoutResponseLocation = uriResolver.resolve(registration.getSingleLogoutServiceResponseLocation());
			registration = registration.mutate()
				.entityId(entityId)
				.singleLogoutServiceLocation(logoutLocation)
				.singleLogoutServiceResponseLocation(logoutResponseLocation)
				.build();
			Saml2MessageBinding saml2MessageBinding = Saml2MessageBindingUtils.resolveBinding(request);
			Saml2LogoutRequest logoutRequest = Saml2LogoutRequest.withRelyingPartyRegistration(registration)
				.samlRequest(serialized)
				.relayState(request.getParameter(Saml2ParameterNames.RELAY_STATE))
				.binding(saml2MessageBinding)
				.parameters((params) -> params.put(Saml2ParameterNames.SIG_ALG,

View on GitHub (pinned to 96852e8860)

Solutions

  1. Verify the RelyingPartyRegistrationRepository registered in the Saml2LogoutConfigurer contains a registration whose registrationId matches the id sent/referenced by the logout request.
  2. Check that the AP's LogoutRequest references an Issuer/entityID that your registrations match; fix relyingPartyRegistrationResolver or repository lookup so it resolves by the same id used to create the authentication.
  3. For dynamic/multi-tenant repositories, ensure the resolve() implementation returns the correct registration for this request (not null) and that tenant resolution runs before the logout filter.
  4. If the registration was legitimately deleted, invalidate the session/authentication so stale registrationIds are not replayed into the logout flow.

Example fix

// before: repository missing the id used by the IdP
@Bean
RelyingPartyRegistrationRepository repo() {
    return new InMemoryRelyingPartyRegistrationRepository(idpA); // only 'idp-a'
}
// after: include the registration the IdP references
@Bean
RelyingPartyRegistrationRepository repo() {
    return new InMemoryRelyingPartyRegistrationRepository(idpA, idpB);
}
Defensive patterns

Strategy: validation

Validate before calling

String registrationId = /* id from request/session */;
RelyingPartyRegistration reg = repository.findByRegistrationId(registrationId);
if (reg == null) {
    throw new ResponseStatusException(HttpStatus.NOT_FOUND,
            "Unknown registrationId: " + registrationId);
}

Try / catch

try {
    filter.doFilterInternal(request, response, chain);
} catch (Saml2AuthenticationException ex) {
    if (Saml2Error.RELYING_PARTY_REGISTRATION_NOT_FOUND.equals(ex.getSaml2Error().getCode())) {
        response.sendError(HttpServletResponse.SC_BAD_REQUEST, ex.getMessage());
    } else { throw ex; }
}

Prevention

When it happens

Trigger: A SAML 2.0 LogoutRequest/LogoutResponse arrives at /logout/saml2/slo and getRegistrationId derives an id (from a stored authentication or request parameter) that this.relyingPartyRegistrationResolver.resolve(request, registrationId) cannot map to a configured RelyingPartyRegistration.

Common situations: Registration was removed or renamed in application config after the user's session/authentication was created; relyingPartyRegistrationRepository does not contain the id referenced by the identity provider (e.g. metadata changed, AP 's' entityID mismatch); multi-tenant setups where a relyingPartyRegistrationRepository is scoped per tenant and the request hits the wrong tenant; spelling/case mismatch in registrationId.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10). Data as JSON: /api/errors/ebf54cbb5f2e529e. Report an issue: GitHub.