Visa Developer Community

Highlighted
Regular Visitor

Java based MLE requests work but C# and NodeJS MLE requests get "Token validation failed"

Hello,

We were able to make successful MLE requests using Java JWE libraries. Both com.nimbusds nimbus-jose-jwt v8.14.1 and org.bitbucket.b_c jose4j v0.7.0 work in the sandbox. However, we're a C# shop and would like to get a C# implementation working. But we were not able to get MLE working in C# MLE. As a sanity check, we also tried NodeJS but that didn't work either.

 

Request

Headers
{
Content-Type: application/json
Accept: application/json
keyId: 4d76f834-dde5-4ea0-af7e-fd22ba020900
Authorization: Basic U0tVMFhaWEg1TDBPNUEwVVA0VEsyMTZ5WEVGVXNiZXRzYVdVc0otcTdhTmc2SjRWazpDZG9tUmszYzBQbTY4UTJwOFNWbzMwSHA=
ex-correlation-id: 0VY6X1AV4WYF_SC
}

Body
{
"encData":"eyJhbGciOiJSU0EtT0FFUC0yNTYiLCJlbmMiOiJBMTI4R0NNIiwia2lkIjoiNGQ3NmY4MzQtZGRlNS00ZWEwLWFmN2UtZmQyMmJhMDIwOTAwIiwiaWF0IjoxNTg4OTcwNjU3fQ.rZPyIYroUvtMu_eBn4SlLUzOpeM9C7-yNF92bgoDCqvMJpx0cia_nKbesUxPBC6U-TJ100T0WQkPQ9ShaknSZkf6tJR5BX3gTed9ed9A8vudcs2wzE9L-DvzOadvzHjQZW3WvniP-T2JMZqst4t_Pq2P0Rr2M4UAsLOmlhGYKh3rM69WjXADKVxVhXows2gM1n-mkTUu1HdHj4U7D5lAvgkLdVq75y6iOD0Q_-_s8kuXImoEjtSJRO7Ngd-IE1pGvUvyjQ6HI_ejnYEfilttO5bZ2cG17C40GlvNGAMe3GtT2BJH4mQECXBYYx-d1RbvA384woHcuz0oqOCC8Lej2w.vE6SszwsjJxtiiVG.ODtUY7fvj_IxHl2ASfjmXOCAE42sxvMNWxTYHDV5RmZ_kdZ_CH2TiUPVQtU-bcj_vLM8a5WLKSZIybHpq9XAJexqx1apTYoTs-KaC3UhK_EYzFKYA_VaJ5ajnIT2CPLPn1FQe7O1iDX6ssgNYRlepj9FUx01wEIsMH5XmEF15ezUihQ_0F52wQrruJGaDQiSi3yydX8B33XDoyMGRo-h5Yx-YloaVUNR_QzAAwcU3SIMb_o-b9PnK1rr9yJutg-coBm6kpqAmsYMHASfgZUa-RfTPQzUfVoBPjL-2Rf2-qPqnhgVkNRICY5JSnGFDkTGdtxJVxIIu2eEbbgmFl3sWQeZZmkuiqEM0WJ8yMsWpgkwEPkNAZDP4KEt-AJ1gJnSS_1c0zhnBcgMyIwJUFbinHrHBGAGRLjbYkym1FFXSS6G5dXjrKS0XP9T62bg2IOAlEqDl_7XezCWcSEMYogQpodj4bAa7V254uPqUvJv_p__kZy8RfntrsH-UKRUv3Nn7RAampFXaeAX6BIOH2qpLTzow1pOcKK0vCmGAaIecfuBn37JaxKnEc_U4gGxBYQP-LuRcrcVONvCxcTJ6wKw_4fMVfXXaVC_JWrUkSw29gJuZdNeoxLhm8_ILoEErkdSBdfmZot2W5V76TRQUjnj59Hx5nGMW-TF8Xq-EFuS7COLnqSKqYr5uJovw7yFnzGZlfigOSHCJRjioANgjt6VOF8ZiXkuea8qNzN4W29spoRC4_KZ0EwkrXtEV05y4xUGSn6jR41sjSL_0XxQa8E7DTMpbksA48dHANA16xVbFDA.kTLYysiXbtCA_j2Xf-vCLA"
}

Response

Headers
{
Server: nginx
X-SERVED-BY: l55c017
X-CORRELATION-ID: 1588970712_323_833486348_l55c017_VDP_WS
X-APP-STATUS: 401
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Strict-Transport-Security: max-age=2592000;includeSubdomains
Cache-Control: no-store, must-revalidate, no-cache
Pragma: no-cache
Date: Fri, 08 May 2020 20:45:12 GMT
Connection: close
Content-Type: application/json; charset=UTF-8
Content-Length: 112
Expires: -1
}

Body
{
"responseStatus":{"status":401,"code":"9210","severity":"ERROR","message":"Token validation failed","info":""}
}

Test Class

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Generic;
using VdpCSharpCore.VDPApiTest.helpers;
using VdpCSharpCore.Mle;

namespace VdpCSharpCore.VDPApiTest.visadirect
{
    [TestClass]
    public class MVisaTest
    {
        private VdpConfig vdpConfig = VdpConfig.Init();
        private string cashInPushPayments;
        private VisaAPIClient visaAPIClient;

        public MVisaTest()
        {
            visaAPIClient = new VisaAPIClient();
            string strDate = DateTime.UtcNow.ToString("yyyy-MM-ddThh:mm:ss");
            cashInPushPayments =
                 "{"
                 + "\"acquirerCountryCode\": \"643\","
                 + "\"acquiringBin\": \"400171\","
                 + "\"amount\": \"124.05\","
                 + "\"businessApplicationId\": \"CI\","
                 + "\"cardAcceptor\": {"
                                         + "\"address\": {"
                                                             + "\"city\": \"Bangalore\","
                                                             + "\"country\": \"IND\""
                                                      + "},"
                                         + "\"idCode\": \"ID-Code123\","
                                         + "\"name\": \"Card Accpector ABC\""
                                       + "},"
                 + "\"localTransactionDateTime\": \"" + strDate + "\","
                 + "\"merchantCategoryCode\": \"4829\","
                 + "\"recipientPrimaryAccountNumber\": \"4123640062698797\","
                 + "\"retrievalReferenceNumber\": \"430000367618\","
                 + "\"senderAccountNumber\": \"4541237895236\","
                 + "\"senderName\": \"Mohammed Qasim\","
                 + "\"senderReference\": \"1234\","
                 + "\"systemsTraceAuditNumber\": \"313042\","
                 + "\"transactionCurrencyCode\": \"USD\","
                 + "\"transactionIdentifier\": \"381228649430015\""
                 + "}";
        }

        [TestMethod]
        public void TestMle_CSharp_Dvsekhvalnov()
        {
            // Implement MLE encryption
            var headers = new Dictionary<string, string>
            {
                { "keyId", vdpConfig.mleKid }
            };

            var jwtService = new DvsekhvalnovJoseJwtService(vdpConfig.mleKid, vdpConfig.mleP12ServerCertPath, vdpConfig.mleP12ServerCertPassword);
            string encData = jwtService.EncryptPayload(cashInPushPayments);
            string requestBodyString = "{\"encData\":\"" + encData + "\"}";

            // Send request
            string baseUri = "visadirect/";
            string resourcePath = "mvisa/v1/cashinpushpayments";
            string status = visaAPIClient.DoMutualAuthCall(baseUri + resourcePath, "POST", "M Visa Transaction Test", requestBodyString, headers);
            Assert.AreEqual(status, "OK");
        }
    }
}

Encryption Service Class

using System;
using System.Collections.Generic;
using System.Security.Cryptography.X509Certificates;

namespace VdpCSharpCore.Mle
{
    // Encryption Library Used: https://github.com/dvsekhvalnov/jose-jwt
    class DvsekhvalnovJoseJwtService
    {
        private readonly string kid;
        private readonly string mlePublicKeyPath;
        private readonly string mlePublicKeyPassword;

        public DvsekhvalnovJoseJwtService(string kid, string mlePublicKeyPath, string mlePublicKeyPassword)
        {
            this.kid = kid;
            this.mlePublicKeyPath = mlePublicKeyPath;
            this.mlePublicKeyPassword = mlePublicKeyPassword;
        }

        public string EncryptPayload(string payload)
        {
            //NET40-NET45
            //var publicKey = new X509Certificate2(mlePublicKeyPath, mlePublicKeyPassword).PublicKey.Key as RSACryptoServiceProvider;

            //NETCORE
            var publicKey = new X509Certificate2(mlePublicKeyPath, mlePublicKeyPassword).GetRSAPublicKey();

            string token = Jose.JWT.Encode(
                payload: payload,
                key: publicKey,
                alg: Jose.JweAlgorithm.RSA_OAEP_256,
                enc: Jose.JweEncryption.A128GCM,
                extraHeaders: new Dictionary<string, object>
                {
                    { "kid", kid },
                    { "iat", Microsoft.IdentityModel.Tokens.EpochTime.GetIntDate(DateTime.UtcNow) }
                });

            return token;
        }
    }
}
2 REPLIES 2
Community Manager

Re: Java based MLE requests work but C# and NodeJS MLE requests get "Token validation failed&qu

Hey @jhollandgtp - sorry to hear that, totally understand the frustrations. Thanks for the info, this will help - let me do some digging and run this by some of our engineers to see what I can get for you. 

 

In the meantime, let me know if any other questions come up. 

 




Was your question answered? Don't forget to click on "Accept as Solution" to help other devs find the answer to the same question.
Highlighted
Regular Visitor

Re: Java based MLE requests work but C# and NodeJS MLE requests get "Token validation failed&am

This is now working with the following update to the encryption code:

            string token = Jose.JWT.Encode(
                payload: payload,
                key: publicKey,
                alg: Jose.JweAlgorithm.RSA_OAEP_256,
                enc: Jose.JweEncryption.A128GCM,
                extraHeaders: new Dictionary<string, object>
                {
                    { "kid", kid },
                    { "iat", new DateTimeOffset(DateTime.UtcNow).ToUnixTimeMilliseconds() }
                });