/// <summary>
        /// Initializes a <see cref="AdfsCreatingTicketContext"/>
        /// </summary>
        /// <param name="context">The HTTP environment.</param>
        /// <param name="options">The options used by the authentication middleware.</param>
        /// <param name="backchannel">The HTTP client used by the authentication middleware</param>
        /// <param name="token">The tokens returned from the token endpoint.</param>
        /// <param name="user">The de-serialized user.</param>
        public AdfsCreatingTicketContext(
            IOwinContext context,
            AdfsOptions options,
            HttpClient backchannel,
            AdfsOAuthTokenResponse token)
            : base(context)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

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

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

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

            TokenResponse = token;
            Backchannel   = backchannel;
            Options       = options;
        }
        /// <summary>
        /// Initializes a <see cref="AdfsCreatingTicketContext"/>
        /// </summary>
        /// <param name="context">The HTTP environment.</param>
        /// <param name="options">The options used by the authentication middleware.</param>
        /// <param name="backchannel">The HTTP client used by the authentication middleware</param>
        /// <param name="token">The tokens returned from the token endpoint.</param>
        /// <param name="user">The de-serialized user.</param>
        public AdfsCreatingTicketContext(
            IOwinContext context,
            AdfsOptions options,
            HttpClient backchannel,
            AdfsOAuthTokenResponse token)
            : base(context)
        {
            if (context == null)
                throw new ArgumentNullException("context");

            if (options == null)
                throw new ArgumentNullException("options");

            if (backchannel == null)
                throw new ArgumentNullException("backchannel");

            if (token == null)
                throw new ArgumentNullException("token");

            TokenResponse = token;
            Backchannel = backchannel;
            Options = options;
        }
        protected virtual async Task <AuthenticationTicket> CreateTicketAsync(
            ClaimsIdentity identity, AuthenticationProperties properties, AdfsOAuthTokenResponse token)
        {
            var claims = CleanClaims(token.Claims).ToList();

            if (!string.IsNullOrEmpty(Options.SubjectClaimType))
            {
                var altSubClaim = claims.FirstOrDefault(c => c.Type == Options.SubjectClaimType);
                if (altSubClaim != null)
                {
                    // replace existing sub claim
                    // TODO: is it safe to leave the existing sub claim alone?
                    claims.RemoveAll(m => m.Type == "sub");
                    claims.Add(new Claim("sub", altSubClaim.Value, altSubClaim.ValueType, token.Issuer));
                }
            }

            if (Options.SaveTokensAsClaims)
            {
                claims.Add(new Claim("access_token", token.AccessToken,
                                     ClaimValueTypes.String, token.Issuer));

                if (!string.IsNullOrEmpty(token.RefreshToken))
                {
                    claims.Add(new Claim("refresh_token", token.RefreshToken,
                                         ClaimValueTypes.String, token.Issuer));
                }

                if (!string.IsNullOrEmpty(token.TokenType))
                {
                    claims.Add(new Claim("token_type", token.TokenType,
                                         ClaimValueTypes.String, token.Issuer));
                }

                if (token.ExpiresIn != 0)
                {
                    claims.Add(new Claim("expires_in", token.ExpiresIn.ToString(),
                                         ClaimValueTypes.String, token.Issuer));
                }
            }

            var ticketIdentity = new ClaimsIdentity(claims, identity.AuthenticationType,
                                                    identity.NameClaimType, identity.RoleClaimType);

            _logger.WriteInformation($"{Options.AuthenticationType}: creating ticket from remote token: {token.AccessToken}");

            var context = new AdfsCreatingTicketContext(Context, Options, _httpClient, token)
            {
                Identity   = ticketIdentity,
                Properties = properties
            };

            await Options.Events.CreatingTicket(context).ConfigureAwait(false);

            if (context.Identity == null)
            {
                _logger.WriteWarning($"{Options.AuthenticationType}: The CreatingTicket event has set the identity to null");
                return(null);
            }

            return(new AuthenticationTicket(context.Identity, context.Properties));
        }