public async Task <List <TokenExchangeResponse> > ProcessExchangeAsync(TokenExchangeRequest tokenExchangeRequest)
        {
            if (tokenExchangeRequest.Extras == null || tokenExchangeRequest.Extras.Count == 0)
            {
                throw new Exception($"{Name}: We require that extras be populated!");
            }
            List <ValidatedToken> validatedIdentityTokens = new List <ValidatedToken>();

            foreach (var item in tokenExchangeRequest.Tokens)
            {
                var principal = await _tokenValidator.ValidateTokenAsync(new TokenDescriptor
                {
                    TokenScheme = item.TokenScheme,
                    Token       = item.Token
                });

                var sub = principal.GetSubjectFromPincipal();
                if (string.IsNullOrEmpty(sub))
                {
                    _summaryLogger.Add("subject", "A subject was not found in the ClaimsPrincipal object!");
                    throw new Exception("A subject was not found in the ClaimsPrincipal object!");
                }
                validatedIdentityTokens.Add(new ValidatedToken
                {
                    Token       = item.Token,
                    TokenScheme = item.TokenScheme,
                    Principal   = principal
                });
            }

            // for this demo, lets assume all the extras are roles.
            var roles = tokenExchangeRequest.Extras;

            roles.Add("user");

            ResourceOwnerTokenRequest resourceOwnerTokenRequest = new ResourceOwnerTokenRequest()
            {
                AccessTokenLifetime = 3600,
                ArbitraryClaims     = new Dictionary <string, List <string> >()
                {
                    { "role", roles }
                },
                Scope    = "offline_access graphQLPlay",
                Subject  = validatedIdentityTokens[0].Principal.GetSubjectFromPincipal(),
                ClientId = "arbitrary-resource-owner-client"
            };

            var resourceOwnerResponse = await _tokenMintingService.MintResourceOwnerTokenAsync(resourceOwnerTokenRequest);

            if (resourceOwnerResponse.IsError)
            {
                throw new Exception(resourceOwnerResponse.Error);
            }

            var tokenExchangeResponse = new TokenExchangeResponse()
            {
                accessToken = new AccessTokenResponse()
                {
                    hint          = nameof(BriarRabbitInProcTokenExchangeHandler),
                    access_token  = resourceOwnerResponse.AccessToken,
                    refresh_token = resourceOwnerResponse.RefreshToken,
                    expires_in    = resourceOwnerResponse.ExpiresIn,
                    token_type    = resourceOwnerResponse.TokenType,
                    authority     =
                        $"{_httpContextAssessor.HttpContext.Request.Scheme}://{_httpContextAssessor.HttpContext.Request.Host}",
                    HttpHeaders = new List <HttpHeader>
                    {
                        new HttpHeader()
                        {
                            Name = "x-authScheme", Value = resourceOwnerResponse.Scheme
                        }
                    }
                }
            };


            IdentityTokenRequest tokenRequest = new IdentityTokenRequest()
            {
                IdentityTokenLifetime = 3600,
                ArbitraryClaims       = new Dictionary <string, List <string> >()
                {
                    { "role", roles }
                },
                Scope    = "graphQLPlay",
                Subject  = validatedIdentityTokens[0].Principal.GetSubjectFromPincipal(),
                ClientId = "arbitrary-resource-owner-client"
            };

            var identityResponse =
                await _tokenMintingService.MintIdentityTokenAsync(tokenRequest);

            if (identityResponse.IsError)
            {
                throw new Exception(identityResponse.Error);
            }
            var identityTokenExchangeResponse = new TokenExchangeResponse()
            {
                IdentityToken = new IdentityTokenResponse()
                {
                    hint       = nameof(BriarRabbitInProcTokenExchangeHandler),
                    id_token   = identityResponse.IdentityToken,
                    expires_in = identityResponse.ExpiresIn,
                    authority  =
                        $"{_httpContextAssessor.HttpContext.Request.Scheme}://{_httpContextAssessor.HttpContext.Request.Host}",
                    HttpHeaders = new List <HttpHeader>
                    {
                        new HttpHeader()
                        {
                            Name = "x-authScheme", Value = identityResponse.Scheme
                        }
                    }
                }
            };

            return(new List <TokenExchangeResponse>()
            {
                new TokenExchangeResponse()
                {
                    customToken = new CustomTokenResponse()
                    {
                        authority = Guid.NewGuid().ToString(),
                        hint = "briar_rabbit/token-exchange-validator/custom",
                        Type = Guid.NewGuid().ToString(),
                        Token = Guid.NewGuid().ToString(),
                        HttpHeaders = new List <HttpHeader>()
                        {
                            new HttpHeader()
                            {
                                Name = Guid.NewGuid().ToString(),
                                Value = Guid.NewGuid().ToString()
                            }
                        }
                    },
                },
                identityTokenExchangeResponse,
                tokenExchangeResponse
            });
        }
        public async Task <List <TokenExchangeResponse> > ProcessExchangeAsync(
            TokenExchangeRequest tokenExchangeRequest,
            Dictionary <string, List <KeyValuePair <string, string> > > mapOpaqueKeyValuePairs)
        {
            var access_token = await GetTokenAsync();

            if (string.IsNullOrEmpty(access_token))
            {
                throw new Exception("Unable to fetch client_credentials access_token");
            }

            var headers = new List <HttpHeader>(_externalExchangeRecord.oAuth2_client_credentials.AdditionalHeaders)
            {
                new HttpHeader()
                {
                    Name = "Authorization", Value = $"Bearer {access_token}"
                },
                new HttpHeader()
                {
                    Name = "Accept", Value = $"application/json"
                }
            };
            var passThrough = _externalExchangeRecord.MintType == "passThroughHandler";
            var externalUrl = passThrough ? _externalExchangeRecord.PassThroughHandler.Url : _externalExchangeRecord.ExternalFinalExchangeHandler.Url;

            (string content, HttpStatusCode statusCode)responseBag;
            using (var httpClient = _defaultHttpClientFactory.HttpClient)
            {
                responseBag = await Utils.EfficientApiCalls.HttpClientHelpers.PostStreamAsync(
                    _defaultHttpClientFactory.HttpClient,
                    externalUrl,
                    headers,
                    new TokenExchangeRequestPackage(tokenExchangeRequest)
                {
                    MapOpaqueKeyValuePairs = mapOpaqueKeyValuePairs
                },
                    CancellationToken.None);
            }

            if (responseBag.statusCode == HttpStatusCode.OK)
            {
                if (passThrough)
                {
                    var passThroughResult = JsonConvert.DeserializeObject <List <TokenExchangeResponse> >(responseBag.content);
                    return(passThroughResult);
                }
                else
                {
                    var tokenExchangeResponses        = new List <TokenExchangeResponse>();
                    var externalExchangeTokenRequests = JsonConvert.DeserializeObject <List <ExternalExchangeTokenResponse> >(responseBag.content);

                    foreach (var externalExchangeResourceOwnerTokenRequest in externalExchangeTokenRequests)
                    {
                        if (externalExchangeResourceOwnerTokenRequest.CustomTokenResponse != null)
                        {
                            var tokenExchangeResponse = new TokenExchangeResponse()
                            {
                                customToken = externalExchangeResourceOwnerTokenRequest.CustomTokenResponse
                            };
                            tokenExchangeResponses.Add(tokenExchangeResponse);
                        }
                        if (externalExchangeResourceOwnerTokenRequest.ArbitraryIdentityTokenRequest != null)
                        {
                            var arbitraryIdentityTokenRequest = externalExchangeResourceOwnerTokenRequest
                                                                .ArbitraryIdentityTokenRequest;
                            IdentityTokenRequest tokenRequest = new IdentityTokenRequest()
                            {
                                IdentityTokenLifetime = arbitraryIdentityTokenRequest.IdentityTokenLifetime,
                                ArbitraryClaims       = arbitraryIdentityTokenRequest.ArbitraryClaims,
                                Scope    = arbitraryIdentityTokenRequest.Scope,
                                Subject  = arbitraryIdentityTokenRequest.Subject,
                                ClientId = _externalExchangeRecord.ExternalFinalExchangeHandler.ClientId // configured value
                            };

                            var response =
                                await _tokenMintingService.MintIdentityTokenAsync(tokenRequest);

                            if (response.IsError)
                            {
                                throw new Exception(response.Error);
                            }
                            var tokenExchangeResponse = new TokenExchangeResponse()
                            {
                                IdentityToken = new IdentityTokenResponse()
                                {
                                    hint       = arbitraryIdentityTokenRequest.Hint,
                                    id_token   = response.IdentityToken,
                                    expires_in = response.ExpiresIn,
                                    authority  =
                                        $"{_httpContextAssessor.HttpContext.Request.Scheme}://{_httpContextAssessor.HttpContext.Request.Host}",
                                    HttpHeaders = arbitraryIdentityTokenRequest.HttpHeaders
                                }
                            };
                            tokenExchangeResponses.Add(tokenExchangeResponse);
                        }

                        if (externalExchangeResourceOwnerTokenRequest.ArbitraryResourceOwnerTokenRequest != null)
                        {
                            var arbitraryResourceOwnerTokenRequest = externalExchangeResourceOwnerTokenRequest
                                                                     .ArbitraryResourceOwnerTokenRequest;
                            ResourceOwnerTokenRequest resourceOwnerTokenRequest = new ResourceOwnerTokenRequest()
                            {
                                AccessTokenLifetime = arbitraryResourceOwnerTokenRequest.AccessTokenLifetime,
                                ArbitraryClaims     = arbitraryResourceOwnerTokenRequest.ArbitraryClaims,
                                Scope    = arbitraryResourceOwnerTokenRequest.Scope,
                                Subject  = arbitraryResourceOwnerTokenRequest.Subject,
                                ClientId = _externalExchangeRecord.ExternalFinalExchangeHandler.ClientId // configured value
                            };

                            var response =
                                await _tokenMintingService.MintResourceOwnerTokenAsync(resourceOwnerTokenRequest);

                            if (response.IsError)
                            {
                                throw new Exception(response.Error);
                            }

                            var tokenExchangeResponse = new TokenExchangeResponse()
                            {
                                accessToken = new AccessTokenResponse()
                                {
                                    hint          = arbitraryResourceOwnerTokenRequest.Hint,
                                    access_token  = response.AccessToken,
                                    refresh_token = response.RefreshToken,
                                    expires_in    = response.ExpiresIn,
                                    token_type    = response.TokenType,
                                    authority     =
                                        $"{_httpContextAssessor.HttpContext.Request.Scheme}://{_httpContextAssessor.HttpContext.Request.Host}",
                                    HttpHeaders = arbitraryResourceOwnerTokenRequest.HttpHeaders
                                }
                            };
                            tokenExchangeResponses.Add(tokenExchangeResponse);
                        }
                    }
                    return(tokenExchangeResponses);
                }
            }

            return(null);
        }