@GetMapping({
        '/' + OidcConstants.BASE_OIDC_URL + '/' + OidcConstants.LOGOUT_URL,
        '/' + OidcConstants.BASE_OIDC_URL + "/logout",
        "/**/" + OidcConstants.LOGOUT_URL
    })
    @Operation(summary = "Handle OIDC logout request",
        parameters = {
            @Parameter(name = OidcConstants.POST_LOGOUT_REDIRECT_URI,
                description = "Post logout redirect URL", in = ParameterIn.QUERY, required = false),
            @Parameter(name = OAuth20Constants.STATE,
                description = "State", in = ParameterIn.QUERY, required = false),
            @Parameter(name = OAuth20Constants.CLIENT_ID,
                description = "Client ID", in = ParameterIn.QUERY, required = false),
            @Parameter(name = OidcConstants.ID_TOKEN_HINT,
                description = "ID Token hint", in = ParameterIn.QUERY, required = false)
        })
    public ResponseEntity handleRequestInternal(
        @RequestParam(value = OidcConstants.POST_LOGOUT_REDIRECT_URI, required = false)
        final String postLogoutRedirectUrl,
        @RequestParam(value = OAuth20Constants.STATE, required = false)
        final String state,
        @RequestParam(value = OAuth20Constants.CLIENT_ID, required = false)
        final String givenClientId,
        @RequestParam(value = OidcConstants.ID_TOKEN_HINT, required = false)
        final String idToken,
        final HttpServletRequest request, final HttpServletResponse response) throws Throwable {

        if (StringUtils.isNotBlank(idToken)) {
            LOGGER.trace("Decoding logout ID token [{}]", idToken);

            val clientIdInIdToken = OAuth20Utils.extractClientIdFromToken(idToken);
            LOGGER.debug("Client id retrieved from ID token is [{}]", clientIdInIdToken);

            if (StringUtils.isNotBlank(givenClientId) && !StringUtils.equalsIgnoreCase(givenClientId, clientIdInIdToken)) {
                LOGGER.warn("Client id [{}] in logout request does not match client id [{}] in ID token", givenClientId, clientIdInIdToken);
                throw new ResponseStatusException(HttpStatus.BAD_REQUEST,
                    configurationContext.getMessageSource().getMessage("screen.oidc.issuer.invalid", ArrayUtils.EMPTY_OBJECT_ARRAY, request.getLocale()));
            }
            val registeredService = OAuth20Utils.getRegisteredOAuthServiceByClientId(
                getConfigurationContext().getServicesManager(), clientIdInIdToken, OidcRegisteredService.class);
            val idTokenClaims = getConfigurationContext().getIdTokenSigningAndEncryptionService().decode(idToken, Optional.of(registeredService));
            Assert.isTrue(idTokenClaims.getClaimValueAsString(OAuth20Constants.CLIENT_ID).equalsIgnoreCase(registeredService.getClientId()),
                "Client id in ID token does not match client id in registered service");
            Assert.isTrue(idTokenClaims.hasClaim(OidcConstants.AUD), "Audience claim is not present");
            Assert.isTrue(idTokenClaims.hasClaim(OAuth20Constants.CLAIM_SUB), "Subject claim is not present");

            LOGGER.debug("Located registered service [{}]", registeredService);
            val service = getConfigurationContext().getWebApplicationServiceServiceFactory().createService(clientIdInIdToken);
            val audit = AuditableContext.builder()
                .service(service)
                .registeredService(registeredService)
                .build();
            val accessResult = getConfigurationContext().getRegisteredServiceAccessStrategyEnforcer().execute(audit);
            accessResult.throwExceptionIfNeeded();

            if (!enforceIssuer(request, response, registeredService)) {
                throw new ResponseStatusException(HttpStatus.BAD_REQUEST,
                    configurationContext.getMessageSource().getMessage("screen.oidc.issuer.invalid", ArrayUtils.EMPTY_OBJECT_ARRAY, request.getLocale()));
            }

            WebUtils.putRegisteredService(request, Objects.requireNonNull(registeredService));
            val urls = getConfigurationContext().getSingleLogoutServiceLogoutUrlBuilder()
                .determineLogoutUrl(registeredService, service, Optional.of(request))
                .stream().map(SingleLogoutUrl::getUrl).collect(Collectors.toList());
            LOGGER.debug("Logout urls assigned to registered service are [{}]", urls);
            if (StringUtils.isNotBlank(postLogoutRedirectUrl) && registeredService.getMatchingStrategy() != null) {
                val postLogoutService = getConfigurationContext().getWebApplicationServiceServiceFactory().createService(postLogoutRedirectUrl);
                val matchResult = registeredService.matches(postLogoutRedirectUrl)
                    || urls.stream().anyMatch(url -> postLogoutRedirectUrlMatcher.matches(postLogoutRedirectUrl, url))
                    || getConfigurationContext().getServicesManager().findServiceBy(postLogoutService) != null;

                if (matchResult) {
                    LOGGER.debug("Requested logout URL [{}] is authorized for redirects", postLogoutRedirectUrl);
                    return executeLogoutRedirect(Optional.ofNullable(StringUtils.trimToNull(state)),
                        Optional.of(postLogoutRedirectUrl), Optional.of(clientIdInIdToken), request, response);
                }
            }
            val validURL = urls.stream().filter(urlValidator::isValid).findFirst();
            if (validURL.isPresent()) {
                return executeLogoutRedirect(Optional.ofNullable(StringUtils.trimToNull(state)),
                    validURL, Optional.of(clientIdInIdToken), request, response);
            }
            LOGGER.debug("No logout urls could be determined for registered service [{}]", registeredService.getName());
        }

        val registeredService = StringUtils.isNotBlank(givenClientId)
            ? OAuth20Utils.getRegisteredOAuthServiceByClientId(getConfigurationContext().getServicesManager(), givenClientId, OidcRegisteredService.class)
            : null;

        if (!enforceIssuer(request, response, registeredService)) {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST,
                configurationContext.getMessageSource().getMessage("screen.oidc.issuer.invalid", ArrayUtils.EMPTY_OBJECT_ARRAY, request.getLocale()));
        }
        return executeLogoutRedirect(Optional.ofNullable(StringUtils.trimToNull(state)),
            Optional.empty(), Optional.ofNullable(givenClientId), request, response);
    }
Handle request.

@param postLogoutRedirectUrl the post logout redirect url
@param state                 the state
@param idToken               the ID token
@param request               the request
@param response              the response
@return the response entity
@throws Exception the exception
support/cas-server-support-oidc-core-api/src/main/java/org/apereo/cas/oidc/web/controllers/logout/OidcLogoutEndpointController.java