/// <summary>
        /// Reads and validates a token encoded in JSON Compact serialized format.
        /// </summary>
        /// <param name="securityToken">A 'JSON Web Token' (JWT) that has been encoded as a JSON object. May be signed using 'JSON Web Signature' (JWS).</param>
        /// <param name="validationParameters">Contains validation parameters for the <see cref="JwtSecurityToken"/>.</param>
        /// <param name="validatedToken">The <see cref="JwtSecurityToken"/> that was validated.</param>
        /// <exception cref="ArgumentNullException">'securityToken' is null or whitespace.</exception>
        /// <exception cref="ArgumentNullException">'validationParameters' is null.</exception>
        /// <exception cref="ArgumentException">'securityToken.Length' > <see cref="MaximumTokenSizeInBytes"/>.</exception>
        /// <returns>A <see cref="ClaimsPrincipal"/> from the jwt. Does not include the header claims.</returns>
        public virtual ClaimsPrincipal ValidateToken(string securityToken, TokenValidationParameters validationParameters, out SecurityToken validatedToken)
        {
            if (string.IsNullOrWhiteSpace(securityToken))
            {
                throw new ArgumentNullException("securityToken");
            }

            if (validationParameters == null)
            {
                throw new ArgumentNullException("validationParameters");
            }

            if (securityToken.Length > MaximumTokenSizeInBytes)
            {
                throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, ErrorMessages.IDX10209, securityToken.Length, MaximumTokenSizeInBytes));
            }

            JwtSecurityToken jwt = this.ValidateSignature(securityToken, validationParameters);

            if (jwt.SigningKey != null)
            {
                this.ValidateIssuerSecurityKey(jwt.SigningKey, jwt, validationParameters);
            }

            DateTime? notBefore = null;
            if (jwt.Payload.Nbf != null)
            {
                notBefore = new DateTime?(jwt.ValidFrom);
            }

            DateTime? expires = null;
            if (jwt.Payload.Exp != null)
            {
                expires = new DateTime?(jwt.ValidTo);
            }

            Validators.ValidateTokenReplay(securityToken, expires, validationParameters);
            if (validationParameters.ValidateLifetime)
            {
                if (validationParameters.LifetimeValidator != null)
                {
                    if (!validationParameters.LifetimeValidator(notBefore: notBefore, expires: expires, securityToken: jwt, validationParameters: validationParameters))
                    {
                        throw new SecurityTokenInvalidLifetimeException(string.Format(CultureInfo.InvariantCulture, ErrorMessages.IDX10230, jwt.ToString()));
                    }
                }
                else
                {
                    ValidateLifetime(notBefore: notBefore, expires: expires, securityToken: jwt, validationParameters: validationParameters);
                }
            }

            if (validationParameters.ValidateAudience)
            {
                if (validationParameters.AudienceValidator != null)
                {
                    if (!validationParameters.AudienceValidator(jwt.Audiences, jwt, validationParameters))
                    {
                        throw new SecurityTokenInvalidAudienceException(string.Format(CultureInfo.InvariantCulture, ErrorMessages.IDX10231, jwt.ToString()));
                    }
                }
                else
                {
                    this.ValidateAudience(jwt.Audiences, jwt, validationParameters);
                }
            }

            string issuer = jwt.Issuer;
            if (validationParameters.ValidateIssuer)
            {
                if (validationParameters.IssuerValidator != null)
                {
                    issuer = validationParameters.IssuerValidator(issuer, jwt, validationParameters);
                }
                else
                {
                    issuer = ValidateIssuer(issuer, jwt, validationParameters);
                }
            }

            if (validationParameters.ValidateActor && !string.IsNullOrWhiteSpace(jwt.Actor))
            {
                SecurityToken actor = null;
                ValidateToken(jwt.Actor, validationParameters, out actor);
            }

            ClaimsIdentity identity = this.CreateClaimsIdentity(jwt, issuer, validationParameters);
            if (validationParameters.SaveSigninToken)
            {
                identity.BootstrapContext = new BootstrapContext(securityToken);
            }

            validatedToken = jwt;
            return new ClaimsPrincipal(identity);
        }
        /// <summary>
        /// Reads and validates a well formed <see cref="SamlSecurityToken"/>.
        /// </summary>
        /// <param name="securityToken">A string containing a well formed securityToken.</param>
        /// <param name="validationParameters">Contains data and information needed for validation.</param>
        /// <param name="validatedToken">The <see cref="Saml2SecurityToken"/> that was validated.</param>
        /// <exception cref="ArgumentNullException">'securityToken' is null or whitespace.</exception>
        /// <exception cref="ArgumentNullException">'validationParameters' is null.</exception>
        /// <exception cref="SecurityTokenException">'securityToken.Length' > <see cref="MaximumTokenSizeInBytes"/>.</exception>
        /// <returns>A <see cref="ClaimsPrincipal"/> generated from the claims in the Saml securityToken.</returns>
        public virtual ClaimsPrincipal ValidateToken(string securityToken, TokenValidationParameters validationParameters, out SecurityToken validatedToken)
        {
            if (string.IsNullOrWhiteSpace(securityToken))
            {
                throw new ArgumentNullException("securityToken");
            }

            if (validationParameters == null)
            {
                throw new ArgumentNullException("validationParameters");
            }

            if (securityToken.Length > MaximumTokenSizeInBytes)
            {
                throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, ErrorMessages.IDX10209, securityToken.Length, MaximumTokenSizeInBytes));
            }

            // Calling System.IdentityModel.Tokens.SamlSecurityTokenHandler requires Configuration and IssuerTokenResolver be set.
            Configuration = new SecurityTokenHandlerConfiguration
            {
                IssuerTokenResolver = new SecurityKeyResolver(securityToken, validationParameters),
                MaxClockSkew = validationParameters.ClockSkew,
            };

            SamlSecurityToken samlToken;
            using (StringReader sr = new StringReader(securityToken))
            {
                using (XmlDictionaryReader reader = XmlDictionaryReader.CreateDictionaryReader(XmlReader.Create(sr)))
                {
                    samlToken = ReadToken(reader, validationParameters) as SamlSecurityToken;
                }
            }

            if (samlToken.Assertion == null)
            {
                throw new ArgumentException(ErrorMessages.IDX10202);
            }

            if (samlToken.Assertion.SigningToken == null && validationParameters.RequireSignedTokens)
            {
                throw new SecurityTokenValidationException(ErrorMessages.IDX10213);
            }

            DateTime? notBefore = null;
            DateTime? expires = null;
            if (samlToken.Assertion.Conditions != null)
            {
                notBefore = samlToken.Assertion.Conditions.NotBefore;
                expires = samlToken.Assertion.Conditions.NotOnOrAfter;
            }

            Validators.ValidateTokenReplay(securityToken, expires, validationParameters);

            if (validationParameters.LifetimeValidator != null)
            {
                validationParameters.LifetimeValidator(notBefore: notBefore, expires: expires, securityToken: samlToken, validationParameters: validationParameters);
            }
            else
            {
                ValidateLifetime(notBefore: notBefore, expires: expires, securityToken: samlToken, validationParameters: validationParameters);
            }

            List<string> audiences = new List<string>();
            if (samlToken.Assertion.Conditions != null && samlToken.Assertion.Conditions.Conditions != null)
            {
                foreach (SamlCondition condition in samlToken.Assertion.Conditions.Conditions)
                {
                    SamlAudienceRestrictionCondition audienceRestriction = condition as SamlAudienceRestrictionCondition;
                    if (null == audienceRestriction)
                    {
                        continue;
                    }

                    foreach (Uri uri in audienceRestriction.Audiences)
                    {
                        audiences.Add(uri.OriginalString);
                    }
                }
            }

            if (validationParameters.AudienceValidator != null)
            {
                validationParameters.AudienceValidator(audiences, samlToken, validationParameters);
            }
            else
            {
                ValidateAudience(audiences, samlToken, validationParameters);
            }

            string issuer = null;
            issuer = samlToken.Assertion.Issuer == null ? null : samlToken.Assertion.Issuer;
            if (validationParameters.IssuerValidator != null)
            {
                issuer = validationParameters.IssuerValidator(issuer, samlToken, validationParameters);
            }
            else
            {
                issuer = ValidateIssuer( issuer, samlToken, validationParameters);
            }

            if (string.IsNullOrWhiteSpace(issuer))
            {
                throw new SecurityTokenInvalidIssuerException(ErrorMessages.IDX10203);
            }

            if (samlToken.Assertion.SigningToken != null)
            {
                ValidateIssuerSecurityKey(samlToken.Assertion.SigningToken.SecurityKeys[0], samlToken, validationParameters);
            }

            ClaimsIdentity claimsIdentity = CreateClaimsIdentity(samlToken, issuer, validationParameters);
            if (validationParameters.SaveSigninToken)
            {
                claimsIdentity.BootstrapContext = new BootstrapContext(securityToken);
            }

            validatedToken = samlToken;
            return new ClaimsPrincipal(claimsIdentity);
        }
        /// <summary>
        /// Reads and validates a well fromed Saml2 securityToken.
        /// </summary>
        /// <param name="securityToken">A Saml2 securityToken.</param>
        /// <param name="validationParameters">Contains data and information needed for validation.</param>
        /// <param name="validatedToken">The <see cref="SamlSecurityToken"/> that was validated.</param>
        /// <exception cref="ArgumentNullException">'securityToken' is null or whitespace.</exception>
        /// <exception cref="ArgumentNullException">'validationParameters' is null.</exception>
        /// <exception cref="ArgumentException">'securityToken.Length' > <see cref="MaximumTokenSizeInBytes"/>.</exception>
        /// <returns>A <see cref="ClaimsPrincipal"/> generated from the claims in the Saml2 securityToken.</returns>
        public virtual ClaimsPrincipal ValidateToken(string securityToken, TokenValidationParameters validationParameters, out SecurityToken validatedToken)
        {
            validatedToken = null;
            if (string.IsNullOrWhiteSpace(securityToken))
            {
                throw new ArgumentNullException("securityToken");
            }

            if (validationParameters == null)
            {
                throw new ArgumentNullException("validationParameters");
            }

            if (securityToken.Length > MaximumTokenSizeInBytes)
            {
                throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, ErrorMessages.IDX10209, securityToken.Length, MaximumTokenSizeInBytes));
            }

            Saml2SecurityToken samlToken;
            using (StringReader sr = new StringReader(securityToken))
            {
                using (XmlDictionaryReader reader = XmlDictionaryReader.CreateDictionaryReader(XmlReader.Create(sr)))
                {
                    samlToken = (new Saml2Handler()
                    {
                        Configuration = new SecurityTokenHandlerConfiguration
                        {
                            IssuerTokenResolver = new SecurityKeyResolver(securityToken, validationParameters),
                            MaxClockSkew = validationParameters.ClockSkew,
                            ServiceTokenResolver = SecurityTokenResolver.CreateDefaultSecurityTokenResolver(validationParameters.ClientDecryptionTokens, true),
                        }
                    }).ReadToken(reader) as Saml2SecurityToken;
                }
            }

            if (samlToken.IssuerToken == null && validationParameters.RequireSignedTokens)
            {
                throw new SecurityTokenValidationException(ErrorMessages.IDX10213);
            }

            if (samlToken.Assertion == null)
            {
                throw new ArgumentException(ErrorMessages.IDX10202);
            }

            DateTime? notBefore = null;
            DateTime? expires = null;
            if (samlToken.Assertion.Conditions != null)
            {
                notBefore = samlToken.Assertion.Conditions.NotBefore;
                expires = samlToken.Assertion.Conditions.NotOnOrAfter;
            }

            Validators.ValidateTokenReplay(securityToken, expires, validationParameters);

            if (validationParameters.LifetimeValidator != null)
            {
                validationParameters.LifetimeValidator(notBefore: notBefore, expires: expires, securityToken: samlToken, validationParameters: validationParameters);
            }
            else
            {
                ValidateLifetime(notBefore: notBefore, expires: expires, securityToken: samlToken, validationParameters: validationParameters);
            }

            // TODO
            // need to validate   ValidateConfirmationData(subjectConfirmation.SubjectConfirmationData);

            List<string> audiences = new List<string>();
            if (samlToken.Assertion.Conditions != null && samlToken.Assertion.Conditions.AudienceRestrictions != null)
            {
                foreach (Saml2AudienceRestriction restriction in samlToken.Assertion.Conditions.AudienceRestrictions)
                {
                    if (restriction==null)
                    {
                        continue;
                    }

                    foreach (Uri uri in restriction.Audiences)
                    {
                        if (uri == null)
                        {
                            continue;
                        }

                        audiences.Add(uri.OriginalString);
                    }
                }
            }

            if (validationParameters.AudienceValidator != null)
            {
                validationParameters.AudienceValidator(audiences, samlToken, validationParameters);
            }
            else
            {
                ValidateAudience(audiences, samlToken, validationParameters);
            }

            string issuer  = samlToken.Assertion.Issuer != null ? samlToken.Assertion.Issuer.Value : null;
            if (validationParameters.IssuerValidator != null)
            {
                issuer = validationParameters.IssuerValidator(issuer, samlToken, validationParameters);
            }
            else
            {
                issuer = ValidateIssuer( issuer, samlToken, validationParameters);
            }

            if (string.IsNullOrWhiteSpace(issuer))
            {
                throw new SecurityTokenInvalidIssuerException(ErrorMessages.IDX10203);
            }

            if (samlToken.IssuerToken != null)
            {
                ValidateIssuerSecurityKey(samlToken.IssuerToken.SecurityKeys[0], samlToken, validationParameters);
            }

            ClaimsIdentity claimsIdentity = CreateClaimsIdentity(samlToken, issuer, validationParameters);
            if (validationParameters.SaveSigninToken)
            {
                claimsIdentity.BootstrapContext = new BootstrapContext(securityToken);
            }

            validatedToken = samlToken;
            return new ClaimsPrincipal(claimsIdentity);
        }
        protected SecurityToken ValidateToken(string securityToken, TokenValidationParameters validationParameters)
        {
            ////////////////////////////////
            // Copied from MS Source Code //
            ////////////////////////////////

            if (string.IsNullOrWhiteSpace(securityToken))
            {
                throw new ArgumentNullException(nameof(securityToken));
            }

            if (validationParameters == null)
            {
                throw new ArgumentNullException(nameof(validationParameters));
            }

            if (securityToken.Length > MaximumTokenSizeInBytes)
            {
                throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, ErrorMessages.IDX10209,
                    securityToken.Length, MaximumTokenSizeInBytes));
            }

            var jwt = ValidateSignature(securityToken, validationParameters);

            if (jwt.SigningKey != null)
            {
                ValidateIssuerSecurityKey(jwt.SigningKey, jwt, validationParameters);
            }

            DateTime? notBefore = null;
            if (jwt.Payload.Nbf != null)
            {
                notBefore = jwt.ValidFrom;
            }

            DateTime? expires = null;
            if (jwt.Payload.Exp != null)
            {
                expires = jwt.ValidTo;
            }

            Validators.ValidateTokenReplay(securityToken, expires, validationParameters);
            if (validationParameters.ValidateLifetime)
            {
                if (validationParameters.LifetimeValidator != null)
                {
                    if (!validationParameters.LifetimeValidator(notBefore, expires, jwt, validationParameters))
                    {
                        throw new SecurityTokenInvalidLifetimeException(string.Format(CultureInfo.InvariantCulture,
                            ErrorMessages.IDX10230, jwt));
                    }
                }
                else
                {
                    ValidateLifetime(notBefore, expires, jwt, validationParameters);
                }
            }

            if (validationParameters.ValidateAudience)
            {
                if (validationParameters.AudienceValidator != null)
                {
                    if (!validationParameters.AudienceValidator(jwt.Audiences, jwt, validationParameters))
                    {
                        throw new SecurityTokenInvalidAudienceException(string.Format(CultureInfo.InvariantCulture,
                            ErrorMessages.IDX10231, jwt));
                    }
                }
                else
                {
                    ValidateAudience(jwt.Audiences, jwt, validationParameters);
                }
            }

            var issuer = jwt.Issuer;
            if (validationParameters.ValidateIssuer)
            {
                issuer = validationParameters.IssuerValidator != null
                    ? validationParameters.IssuerValidator(issuer, jwt, validationParameters)
                    : ValidateIssuer(issuer, jwt, validationParameters);
            }

            if (validationParameters.ValidateActor && !string.IsNullOrWhiteSpace(jwt.Actor))
            {
                SecurityToken actor;
                ValidateToken(jwt.Actor, validationParameters, out actor);
            }

            return jwt;
        }