protected RegisteredService reconcile(final OidcRegisteredService oidcService) {
        LOGGER.trace("Reconciling OpenID Connect scopes and claims for [{}]", oidcService.getServiceId());

        val definedServiceScopes = oidcService.getScopes();
        if (definedServiceScopes.isEmpty()) {
            LOGGER.trace("Registered service [{}] does not define any scopes to control attribute release policies. "
                    + "CAS will allow the existing attribute release policies assigned to the service to operate without a scope.",
                oidcService.getServiceId());
            return oidcService;
        }

        val userScopes = attributeReleasePolicyFactory.getUserDefinedScopes();
        val customClaims = new ArrayList<String>();
        val policyChain = new ChainingAttributeReleasePolicy();

        definedServiceScopes.forEach(givenScope -> {
            LOGGER.trace("Reviewing scope [{}] for [{}]", givenScope, oidcService.getServiceId());

            val userDefinedScope = Arrays.stream(OidcConstants.StandardScopes.values())
                .noneMatch(scope -> scope.getScope().trim().equalsIgnoreCase(givenScope.trim()));
            if (userDefinedScope) {
                LOGGER.debug("[{}] appears to be a user-defined scope and does not match any of the predefined standard scopes. "
                    + "Checking [{}] against user-defined scopes provided as [{}]", givenScope, givenScope, userScopes);
                userScopes
                    .stream()
                    .filter(scope -> scope.getScopeName().equals(givenScope.trim()))
                    .findFirst()
                    .ifPresentOrElse(
                        userPolicy -> addAttributeReleasePolicy(policyChain, userPolicy, givenScope, oidcService),
                        () -> customClaims.add(givenScope.trim()));
            } else {
                val scope = OidcConstants.StandardScopes.valueOf(givenScope.trim().toUpperCase(Locale.ENGLISH));
                switch (scope) {
                    case EMAIL, ADDRESS, PROFILE, PHONE, ASSURANCE -> {
                        val policyToAdd = attributeReleasePolicyFactory.get(scope);
                        addAttributeReleasePolicy(policyChain, policyToAdd, givenScope, oidcService);
                    }
                    case OPENID, DEVICE_SSO -> LOGGER.debug("Scope [{}] is found for service [{}]", givenScope, oidcService.getId());
                    case OFFLINE_ACCESS -> {
                        LOGGER.debug("Given scope [{}], service [{}] is marked to generate refresh tokens", givenScope, oidcService.getId());
                        oidcService.setGenerateRefreshToken(true);
                    }
                }
            }
        });
        if (!customClaims.isEmpty()) {
            val userPolicy = attributeReleasePolicyFactory.custom(OidcConstants.CUSTOM_SCOPE_TYPE, customClaims);
            addAttributeReleasePolicy(policyChain, userPolicy, userPolicy.getScopeName(), oidcService);
        }

        val scopeFree = definedServiceScopes.isEmpty()
            || (definedServiceScopes.size() == 1 && definedServiceScopes.contains(OidcConstants.StandardScopes.OPENID.getScope()))
            || oidcService.getAttributeReleasePolicy() instanceof OidcScopeFreeAttributeReleasePolicy
            || (oidcService.getAttributeReleasePolicy() instanceof final RegisteredServiceChainingAttributeReleasePolicy chain
                && chain.getPolicies().stream().anyMatch(OidcScopeFreeAttributeReleasePolicy.class::isInstance));
        if (scopeFree) {
            LOGGER.trace("Service definition [{}] will use the assigned attribute release policy without scopes", oidcService.getName());

            if (oidcService.getAttributeReleasePolicy() instanceof final RegisteredServiceChainingAttributeReleasePolicy chain) {
                policyChain.addPolicies(chain.getPolicies().toArray(new RegisteredServiceAttributeReleasePolicy[0]));
            } else {
                policyChain.addPolicies(oidcService.getAttributeReleasePolicy());
            }
        }
        if (policyChain.getPolicies().isEmpty()) {
            LOGGER.debug("No attribute release policy could be determined based on given scopes. "
                + "No claims/attributes will be released to [{}]", oidcService.getServiceId());
            oidcService.setAttributeReleasePolicy(new DenyAllAttributeReleasePolicy());
        } else {
            if (policyChain.size() == 1) {
                oidcService.setAttributeReleasePolicy(policyChain.getPolicies().getFirst());
            } else {
                oidcService.setAttributeReleasePolicy(policyChain);
            }
        }

        LOGGER.trace("Scope/claim reconciliation for service [{}] resulted in the following attribute release policy [{}]",
            oidcService.getServiceId(), oidcService.getAttributeReleasePolicy());

        return oidcService;
    }
This is {@link OidcServiceRegistryListener}.

@author Misagh Moayyed
@since 6.1.0
support/cas-server-support-oidc-core-api/src/main/java/org/apereo/cas/oidc/services/OidcServiceRegistryListener.java