/// <summary>Validates the JWT token.</summary>
        /// <param name="jwtTokenString"></param>
        /// <param name="subject"></param>
        /// <returns>
        ///   <c>true</c> if XXXX, <c>false</c> otherwise.</returns>
        /// <remarks>This would be used server side</remarks>
        public static (bool isTokenValid, string validatedUsername, JwtSecurityToken jwtToken) ValidateJWTToken(string jwtTokenString, string audience)
        {
            // determine who the caller claims to be (as identified by the private key they used)
            // the private key they used is identified by the kid parameter in the JWT header
            JwtSecurityToken jwtToken = new JwtSecurityToken(jwtTokenString);
            //string signingKeyThumbprint = jwtToken.Header.Kid;

            // find the user that should be associated with the supplied thumbprint
            //var userInfo = UserController.GetUserWithKeyThumbprint(signingKeyThumbprint);
            string clientID = jwtToken.GetPayloadValue(CLIENT_ID_CLAIM_NAME);
            var    userInfo = UserController.GetUserWithClientID(clientID);

            if (userInfo == null)
            {
                // fail if thumbprint is not associated with a user in our user repo
                return(false, string.Empty, null);
            }

            if (!userInfo.IsEnabled)
            {
                // fail if user is marked disabled in the User Repo
                return(false, string.Empty, null);
            }

            if (jwtToken.Payload.Sub.ToLower() != userInfo.Company.ToLower())
            {
                // fail if sub(ject) value in token payload does not match the value on the user record
                return(false, string.Empty, null);
            }

            if (!jwtToken.Payload.ContainsKey(CLIENT_ID_CLAIM_NAME) || ((string)jwtToken.Payload[CLIENT_ID_CLAIM_NAME] != userInfo.ClientID.ToLower()))
            {
                // fail if Client id value in token payload does not match the value on the user record
                return(false, string.Empty, null);
            }



            // create a security key from the certificate
            SecurityKey key = null;

            if (!_valdiateCache.TryGetValue(userInfo.KeyThumbprint, out key))
            {
                // load the cert we want to use to validate the JWT
                var certificate = CertificateController.GetCertificateWithThumbprint(userInfo.KeyThumbprint);
                key = new X509SecurityKey(certificate);

                _valdiateCache.Add(userInfo.KeyThumbprint, key);
            }

            // setup the token validation parameters
            TokenValidationParameters validationParameters =
                new TokenValidationParameters
            {
                ValidateIssuer    = false,
                ValidateAudience  = true,
                ValidAudiences    = new[] { audience },
                IssuerSigningKeys = new List <SecurityKey>()
                {
                    key
                }
            };

            // try and validate the token
            // if we can validate the JWT using the cert... we use that as a surrogate method for authentication
            SecurityToken           validatedToken;
            JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler();

            try
            {
                handler.ValidateToken(jwtTokenString, validationParameters, out validatedToken);

                // validation succeeded
                return(true, userInfo.User, jwtToken);
            }
            catch
            {
                // validation fails
                return(false, string.Empty, null);
            }
        }
        /// <summary>Creates the JWT token.</summary>
        /// <param name="userName"></param>
        /// <param name="subject">The subject.</param>
        /// <param name="audience">The audience.</param>
        /// <param name="ttlMinutes">The ttlMinutes.</param>
        /// <param name="httpBody">The httpBody.</param>
        /// <returns>System.String.</returns>
        /// <remarks>This would be used on the client side</remarks>
        public static string CreateJWTToken(string userName, string subject, string audience, int ttlMinutes, string httpBody)
        {
            JwtHeader header   = null;
            var       userInfo = UserController.GetUserInfo(userName);

            if (!_createCache.TryGetValue(userName, out header))
            {
                if (ttlMinutes < 1 || ttlMinutes > 30)
                {
                    throw new ArgumentException($"ttlMinutes paramter value of: [{ttlMinutes}] must be from 1 to 30");
                }

                // Load the Certificate
                var certificate = CertificateController.GetCertificateWithThumbprint(userInfo.KeyThumbprint);

                // Represents the cryptographic key and security algorithms that are used to generate a digital signature.
                var credentials = new SigningCredentials(new X509SecurityKey(certificate), "RS256");

                // Create a header class that will use the supplied credentials
                header = new JwtHeader(credentials);

                // add to the cache
                _createCache.Add(userName, header);
            }

            // Define the JWT Payload
            //  Note: the specifc content required for this use case (Purchase Auth) needs to be determined
            JwtPayload payload = null;

            if (!string.IsNullOrEmpty(httpBody))
            {
                payload = new JwtPayload
                {
                    { "sub", subject },
                    { "aud", audience },
                    { "exp", DateTime.UtcNow.AddMinutes(ttlMinutes).ToEpochSeconds() },
                    { CLIENT_ID_CLAIM_NAME, userInfo.ClientID },
                    { BODYHASH_CLAIM_NAME, httpBody.SHA256Hash() },
                    { HASHTYPE_CLAIM_NAME, @"sha256" }
                };
            }
            else
            {
                payload = new JwtPayload
                {
                    { "sub", subject },
                    { "aud", audience },
                    { "exp", DateTime.UtcNow.AddMinutes(15).ToEpochSeconds() },
                };
            }

            // create the JWT
            var secToken = new JwtSecurityToken(header, payload);
            var handler  = new JwtSecurityTokenHandler();

            // convert the Token to a String
            handler.TokenLifetimeInMinutes = ttlMinutes;
            var tokenString = handler.WriteToken(secToken);

            /*
             *  Sample JWT generated
             *  eyJhbGciOiJSUzI1NiIsImtpZCI6IjFERTJERjQ2NkQyMTg4RDMyRjc0ODdCMjlCQzc2OTExNURDNTM0NzIiLCJ0eXAiOiJKV1QifQ.eyJzdWIiOiJodHRwczovL3d3dy5kYXRhY2Fwc3lzdGVtcy5jb20vIiwiYXVkIjoiaHR0cHM6Ly93d3cud29ybGRwYXkuY29tLyIsImV4cCI6MTU2NTAzNjcyMCwiYm9keWhhc2giOiI4NTFkOTNkMjMwYmE0ZThiMzVkNWE1ZjUwYWY3N2Q2MDgxNmJiY2ZjZGM4NWE4ODUwODZkMzhiZDVjMzM5NjViIiwiaGFzaHR5cGUiOiJzaGEyNTYifQ.bD_Aw72U9niNcy_SWdmmSyb_bcpWe6itbni5D0TunC3lf3_SkGWwnWKRlWViwp59VtC6Vj0B3M5ouXvQ1aI4ehsB6R03uAMkh4zW5HQKhccbInhtpNSeOmGh2IsjZfBK2w8_gs7z3Wsqhvio9N2PTWq9wtAuVUdNCeaBBhtsr_WP8QQjLpm0GswqGLARZc07Rw6bxOIHASsF-4Doy-huDLmydBggjO5YS2y2Wp2_MFmCIawCYvnnrSnhxzvZ1iz7bIwHX614VPlDHc2PlspLp7Lal5oJTOBoh284njuOgVlxwKaW2YjZS0W3dmUgNrro3_JDEvWeJvvgiRXk58bXdw
             *
             *  using https://jwt.io/
             *  Header
             *  {
             *    "alg": "RS256",
             *    "kid": "1DE2DF466D2188D32F7487B29BC769115DC53472",
             *    "typ": "JWT"
             *  }
             *
             *  Payload
             *  {
             *    "sub": "https://www.datacapsystems.com/",
             *    "aud": "https://www.worldpay.com/",
             *    "exp": 1565036720,
             *    "bodyhash": "851d93d230ba4e8b35d5a5f50af77d60816bbcfcdc85a885086d38bd5c33965b",
             *    "hashtype": "sha256"
             *  }
             */

            return(tokenString);
        }
        public static string CreateDownstreamJWTToken(string userName, string subject, string audience, int ttlMinutes, string upstreamjwt)
        {
            var userInfo = UserController.GetUserInfo(userName);

            if (ttlMinutes < 1 || ttlMinutes > 10)
            {
                throw new ArgumentException($"ttlMinutes paramter value of: [{ttlMinutes}] must be from 1 to 10");
            }

            // Load the Certificate
            var certificate = CertificateController.GetCertificateForDP();

            #region Experimenting with Pubic Key
            string publicKey = certificate.GetPublicKeyString();
            byte[] bytes     = new byte[publicKey.Length * sizeof(char)];
            System.Buffer.BlockCopy(publicKey.ToCharArray(), 0, bytes, 0, bytes.Length);

            // ===================
            //Create a new instance of RSACryptoServiceProvider.
            RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();

            //Get an instance of RSAParameters from ExportParameters function.
            RSAParameters RSAKeyInfo = RSA.ExportParameters(false);

            //Set RSAKeyInfo to the public key values.
            RSAKeyInfo.Modulus = bytes;
            //Import key parameters into RSA.
            RSA.ImportParameters(RSAKeyInfo);
            // ===================
            #endregion

            // Represents the cryptographic key and security algorithms that are used to generate a digital signature.
            var credentials = new SigningCredentials(new X509SecurityKey(certificate), "RS256");

            // Create a header class that will use the supplied credentials
            var header = new JwtHeader(credentials);

            // Define the JWT Payload
            //  Note: the specifc content required for this use case (Purchase Auth) needs to be determined
            JwtPayload payload = new JwtPayload
            {
                { "sub", subject },
                { "aud", audience },
                { "exp", DateTime.UtcNow.AddMinutes(15).ToEpochSeconds() },
                { "ujwt", upstreamjwt },
            };

            // create the JWT
            var secToken = new JwtSecurityToken(header, payload);
            var handler  = new JwtSecurityTokenHandler();

            // convert the Token to a String
            var tokenString = handler.WriteToken(secToken);

            /*
             *  Sample JWT generated
             *  eyJhbGciOiJSUzI1NiIsImtpZCI6IjFERTJERjQ2NkQyMTg4RDMyRjc0ODdCMjlCQzc2OTExNURDNTM0NzIiLCJ0eXAiOiJKV1QifQ.eyJzdWIiOiJodHRwczovL3d3dy5kYXRhY2Fwc3lzdGVtcy5jb20vIiwiYXVkIjoiaHR0cHM6Ly93d3cud29ybGRwYXkuY29tLyIsImV4cCI6MTU2NTAzNjcyMCwiYm9keWhhc2giOiI4NTFkOTNkMjMwYmE0ZThiMzVkNWE1ZjUwYWY3N2Q2MDgxNmJiY2ZjZGM4NWE4ODUwODZkMzhiZDVjMzM5NjViIiwiaGFzaHR5cGUiOiJzaGEyNTYifQ.bD_Aw72U9niNcy_SWdmmSyb_bcpWe6itbni5D0TunC3lf3_SkGWwnWKRlWViwp59VtC6Vj0B3M5ouXvQ1aI4ehsB6R03uAMkh4zW5HQKhccbInhtpNSeOmGh2IsjZfBK2w8_gs7z3Wsqhvio9N2PTWq9wtAuVUdNCeaBBhtsr_WP8QQjLpm0GswqGLARZc07Rw6bxOIHASsF-4Doy-huDLmydBggjO5YS2y2Wp2_MFmCIawCYvnnrSnhxzvZ1iz7bIwHX614VPlDHc2PlspLp7Lal5oJTOBoh284njuOgVlxwKaW2YjZS0W3dmUgNrro3_JDEvWeJvvgiRXk58bXdw
             *
             *  using https://jwt.io/
             *  Header
             *  {
             *    "alg": "RS256",
             *    "kid": "1DE2DF466D2188D32F7487B29BC769115DC53472",
             *    "typ": "JWT"
             *  }
             *
             *  Payload
             *  {
             *    "sub": "https://www.datacapsystems.com/",
             *    "aud": "https://www.worldpay.com/",
             *    "exp": 1565036720,
             *    "bodyhash": "851d93d230ba4e8b35d5a5f50af77d60816bbcfcdc85a885086d38bd5c33965b",
             *    "hashtype": "sha256"
             *  }
             */

            return(tokenString);
        }