protected virtual Task <TokenValidationResult> ValidateJwtAccessTokenAsync(string jwt)
        {
            var handler = new JwtSecurityTokenHandler();

            handler.Configuration = new SecurityTokenHandlerConfiguration();
            handler.Configuration.CertificateValidationMode = X509CertificateValidationMode.None;
            handler.Configuration.CertificateValidator      = X509CertificateValidator.None;

            var parameters = new TokenValidationParameters
            {
                ValidIssuer     = _settings.GetIssuerUri(),
                SigningToken    = new X509SecurityToken(_settings.GetSigningCertificate()),
                AllowedAudience = string.Format(Constants.AccessTokenAudience, _settings.GetIssuerUri())
            };

            try
            {
                var id = handler.ValidateToken(jwt, parameters);

                return(Task.FromResult(new TokenValidationResult
                {
                    Claims = id.Claims
                }));
            }
            catch (Exception ex)
            {
                _logger.ErrorFormat("JWT token validation error: {0}", ex.ToString());

                return(Task.FromResult(new TokenValidationResult
                {
                    IsError = true,
                    Error = Constants.ProtectedResourceErrors.InvalidToken
                }));
            }
        }
        public virtual async Task <Token> CreateIdentityTokenAsync(ClaimsPrincipal subject, Client client, IEnumerable <Scope> scopes, bool includeAllIdentityClaims, NameValueCollection request, string accessTokenToHash = null)
        {
            // host provided claims
            var claims = new List <Claim>();

            // if nonce was sent, must be mirrored in id token
            var nonce = request.Get(Constants.AuthorizeRequest.Nonce);

            if (nonce.IsPresent())
            {
                claims.Add(new Claim(Constants.ClaimTypes.Nonce, nonce));
            }

            // add iat claim
            claims.Add(new Claim(Constants.ClaimTypes.IssuedAt, DateTime.UtcNow.ToEpochTime().ToString(), ClaimValueTypes.Integer));

            // add at_hash claim
            if (accessTokenToHash.IsPresent())
            {
                claims.Add(new Claim(Constants.ClaimTypes.AccessTokenHash, HashAccessToken(accessTokenToHash)));
            }

            claims.AddRange(await _claimsProvider.GetIdentityTokenClaimsAsync(
                                subject,
                                client,
                                scopes,
                                _settings,
                                includeAllIdentityClaims,
                                _users,
                                request));

            var token = new Token(Constants.TokenTypes.IdentityToken)
            {
                Audience = client.ClientId,
                Issuer   = _settings.GetIssuerUri(),
                Lifetime = client.IdentityTokenLifetime,
                Claims   = claims.Distinct(new ClaimComparer()).ToList(),
                Client   = client
            };

            return(token);
        }
        public async Task <dynamic> GetConfiguration()
        {
            var baseUrl = Request.GetBaseUrl(_settings.GetPublicHost());
            var scopes  = await _settings.GetScopesAsync();

            return(new
            {
                issuer = _settings.GetIssuerUri(),
                jwks_uri = baseUrl + ".well-known/jwks",
                authorization_endpoint = baseUrl + "connect/authorize",
                token_endpoint = baseUrl + "connect/token",
                userinfo_endpoint = baseUrl + "connect/userinfo",
                end_session_endpoint = baseUrl + "connect/logout",
                scopes_supported = scopes.Select(s => s.Name),
                response_types_supported = Constants.SupportedResponseTypes,
                response_modes_supported = Constants.SupportedResponseModes,
                grant_types_supported = Constants.SupportedGrantTypes,
                subject_types_support = new string[] { "pairwise", "public" },
                id_token_signing_alg_values_supported = "RS256"
            });
        }