/// <summary>
        /// Creates an identity token.
        /// </summary>
        /// <param name="request">The token creation request.</param>
        /// <returns>
        /// An identity token
        /// </returns>
        public virtual async Task <Token> CreateIdentityTokenAsync(TokenCreationRequest request)
        {
            Logger.LogTrace("Creating identity token");
            request.Validate();

            // host provided claims
            var claims = new List <Claim>();

            // if nonce was sent, must be mirrored in id token
            if (request.Nonce.IsPresent())
            {
                claims.Add(new Claim(JwtClaimTypes.Nonce, request.Nonce));
            }

            // add iat claim
            claims.Add(new Claim(JwtClaimTypes.IssuedAt, IdentityServerDateTime.UtcNow.ToEpochTime().ToString(), ClaimValueTypes.Integer));

            // add at_hash claim
            if (request.AccessTokenToHash.IsPresent())
            {
                claims.Add(new Claim(JwtClaimTypes.AccessTokenHash, HashAdditionalData(request.AccessTokenToHash)));
            }

            // add c_hash claim
            if (request.AuthorizationCodeToHash.IsPresent())
            {
                claims.Add(new Claim(JwtClaimTypes.AuthorizationCodeHash, HashAdditionalData(request.AuthorizationCodeToHash)));
            }

            // add sid if present
            if (request.ValidatedRequest.SessionId.IsPresent())
            {
                claims.Add(new Claim(JwtClaimTypes.SessionId, request.ValidatedRequest.SessionId));
            }

            claims.AddRange(await ClaimsProvider.GetIdentityTokenClaimsAsync(
                                request.Subject,
                                request.ValidatedRequest.Client,
                                request.Resources,
                                request.IncludeAllIdentityClaims,
                                request.ValidatedRequest));

            var issuer = Context.HttpContext.GetIdentityServerIssuerUri();

            var token = new Token(OidcConstants.TokenTypes.IdentityToken)
            {
                Audiences       = { request.ValidatedRequest.Client.ClientId },
                Issuer          = issuer,
                Lifetime        = request.ValidatedRequest.Client.IdentityTokenLifetime,
                Claims          = claims.Distinct(new ClaimComparer()).ToList(),
                ClientId        = request.ValidatedRequest.Client.ClientId,
                AccessTokenType = request.ValidatedRequest.AccessTokenType
            };

            return(token);
        }
        public virtual async Task <Token> CreateIdentityTokenAsync(TokenCreationRequest request)
        {
            Logger.LogTrace("Creating identity token");
            request.Validate();
            string       algorithm = ((await KeyMaterialService.GetSigningCredentialsAsync(request.ValidatedRequest.Client.AllowedIdentityTokenSigningAlgorithms)) ?? throw new InvalidOperationException("No signing credential is configured.")).Algorithm;
            List <Claim> claims    = new List <Claim>();

            if (request.Nonce.IsPresent())
            {
                claims.Add(new Claim("nonce", request.Nonce));
            }
            claims.Add(new Claim("iat", Clock.UtcNow.ToUnixTimeSeconds().ToString(), "http://www.w3.org/2001/XMLSchema#integer64"));
            if (request.AccessTokenToHash.IsPresent())
            {
                claims.Add(new Claim("at_hash", CryptoHelper.CreateHashClaimValue(request.AccessTokenToHash, algorithm)));
            }
            if (request.AuthorizationCodeToHash.IsPresent())
            {
                claims.Add(new Claim("c_hash", CryptoHelper.CreateHashClaimValue(request.AuthorizationCodeToHash, algorithm)));
            }
            if (request.StateHash.IsPresent())
            {
                claims.Add(new Claim("s_hash", request.StateHash));
            }
            if (request.ValidatedRequest.SessionId.IsPresent())
            {
                claims.Add(new Claim("sid", request.ValidatedRequest.SessionId));
            }
            List <Claim> list = claims;

            list.AddRange(await ClaimsProvider.GetIdentityTokenClaimsAsync(request.Subject, request.ValidatedResources, request.IncludeAllIdentityClaims, request.ValidatedRequest));
            string identityServerIssuerUri = ContextAccessor.HttpContext.GetIdentityServerIssuerUri();

            return(new Token("id_token")
            {
                CreationTime = Clock.UtcNow.UtcDateTime,
                Audiences =
                {
                    request.ValidatedRequest.Client.ClientId
                },
                Issuer = identityServerIssuerUri,
                Lifetime = request.ValidatedRequest.Client.IdentityTokenLifetime,
                Claims = claims.Distinct(new ClaimComparer()).ToList(),
                ClientId = request.ValidatedRequest.Client.ClientId,
                AccessTokenType = request.ValidatedRequest.AccessTokenType,
                AllowedSigningAlgorithms = request.ValidatedRequest.Client.AllowedIdentityTokenSigningAlgorithms
            });
        }
        /// <summary>
        /// Creates an identity token.
        /// </summary>
        /// <param name="request">The token creation request.</param>
        /// <returns>
        /// An identity token
        /// </returns>
        public virtual async Task <Token> CreateIdentityTokenAsync(TokenCreationRequest request)
        {
            Logger.LogTrace("Creating identity token");
            request.Validate();

            // todo: Dom, add a test for this. validate the at and c hashes are correct for the id_token when the client's alg doesn't match the server default.
            var credential = await KeyMaterialService.GetSigningCredentialsAsync(request.ValidatedRequest.Client.AllowedIdentityTokenSigningAlgorithms);

            if (credential == null)
            {
                throw new InvalidOperationException("No signing credential is configured.");
            }

            var signingAlgorithm = credential.Algorithm;

            // host provided claims
            var claims = new List <Claim>();

            // if nonce was sent, must be mirrored in id token
            if (request.Nonce.IsPresent())
            {
                claims.Add(new Claim(JwtClaimTypes.Nonce, request.Nonce));
            }

            // add iat claim
            claims.Add(new Claim(JwtClaimTypes.IssuedAt, Clock.UtcNow.ToUnixTimeSeconds().ToString(), ClaimValueTypes.Integer64));

            // add at_hash claim
            if (request.AccessTokenToHash.IsPresent())
            {
                claims.Add(new Claim(JwtClaimTypes.AccessTokenHash, CryptoHelper.CreateHashClaimValue(request.AccessTokenToHash, signingAlgorithm)));
            }

            // add c_hash claim
            if (request.AuthorizationCodeToHash.IsPresent())
            {
                claims.Add(new Claim(JwtClaimTypes.AuthorizationCodeHash, CryptoHelper.CreateHashClaimValue(request.AuthorizationCodeToHash, signingAlgorithm)));
            }

            // add s_hash claim
            if (request.StateHash.IsPresent())
            {
                claims.Add(new Claim(JwtClaimTypes.StateHash, request.StateHash));
            }

            // add sid if present
            if (request.ValidatedRequest.SessionId.IsPresent())
            {
                claims.Add(new Claim(JwtClaimTypes.SessionId, request.ValidatedRequest.SessionId));
            }

            claims.AddRange(await ClaimsProvider.GetIdentityTokenClaimsAsync(
                                request.Subject,
                                request.ValidatedResources,
                                request.IncludeAllIdentityClaims,
                                request.ValidatedRequest));

            var issuer = ContextAccessor.HttpContext.GetIdentityServerIssuerUri();

            var token = new Token(OidcConstants.TokenTypes.IdentityToken)
            {
                CreationTime             = Clock.UtcNow.UtcDateTime,
                Audiences                = { request.ValidatedRequest.Client.ClientId },
                Issuer                   = issuer,
                Lifetime                 = request.ValidatedRequest.Client.IdentityTokenLifetime,
                Claims                   = claims.Distinct(new ClaimComparer()).ToList(),
                ClientId                 = request.ValidatedRequest.Client.ClientId,
                AccessTokenType          = request.ValidatedRequest.AccessTokenType,
                AllowedSigningAlgorithms = request.ValidatedRequest.Client.AllowedIdentityTokenSigningAlgorithms
            };

            return(token);
        }