@Override
    public String parseToken(final String token) {
        try {
            val json = this.cipherExecutor.decode(token);
            val claims = JwtClaims.parse(json);
            val resetProperties = casProperties.getAuthn().getPm().getReset();
            val issuer = casProperties.getServer().getPrefix();
            
            if (!claims.getIssuer().equals(issuer)) {
                LOGGER.error("Token issuer does not match CAS");
                return null;
            }
            if (claims.getAudience().isEmpty() || !claims.getAudience().getFirst().equals(issuer)) {
                LOGGER.error("Token audience does not match CAS");
                return null;
            }
            if (StringUtils.isBlank(claims.getSubject())) {
                LOGGER.error("Token has no subject identifier");
                return null;
            }

            val holder = ClientInfoHolder.getClientInfo();
            if (resetProperties.isIncludeServerIpAddress() && !claims.getStringClaimValue("origin").equals(holder.getServerIpAddress())) {
                LOGGER.error("Token origin server IP address does not match CAS");
                return null;
            }
            if (resetProperties.isIncludeClientIpAddress() && !claims.getStringClaimValue("client").equals(holder.getClientIpAddress())) {
                LOGGER.error("Token client IP address does not match CAS");
                return null;
            }

            val expirationTime = claims.getExpirationTime();
            if (expirationTime.isBefore(NumericDate.now())) {
                LOGGER.error("Token has expired.");
                return null;
            }
            return claims.getSubject();
        } catch (final Exception e) {
            LoggingUtils.error(LOGGER, e);
        }
        return null;
    }
This is {@link BasePasswordManagementService}.

@author Misagh Moayyed
@since 5.1.0
support/cas-server-support-pm-core/src/main/java/org/apereo/cas/pm/impl/BasePasswordManagementService.java