Naveed Ahmed
Naveed Ahmed

Reputation: 10386

ASP.Net MVC 5 How to encrypt JWT Tokens

I have gone throw few posts about using JWT in ASP.Net MVC, which guides how to issue and consume Signed JSON Web Tokens.

Can anyone please guide how to issue and consume encrypted JWT following the JSON Web Encryption (JWE) specifications in case we need to transmit some sensitive data in the JWT payload.

Upvotes: 0

Views: 2546

Answers (1)

Divyang Desai
Divyang Desai

Reputation: 7866

Understanding JWT

JSON Web Token (JWT) is a compact URL-safe means of representing claims to be transferred between two parties. The claims in a JWT are encoded as a JavaScript Object Notation (JSON) object that is used as the payload of a JSON Web Signature (JWS) structure or as the plaintext of a JSON Web Encryption (JWE) structure, enabling the claims to be digitally signed or MACed and/or encrypted.

What JWT?
https://jwt.io/introduction/

Json Web Token Standards
https://datatracker.ietf.org/doc/html/draft-ietf-oauth-json-web-token-25

Anatomy of JWT
https://scotch.io/tutorials/the-anatomy-of-a-json-web-token

Creating JSON Web Token in JavaScript
https://www.jonathan-petitcolas.com/2014/11/27/creating-json-web-token-in-javascript.html

Now, We understand JWT call and how we can serve it from server side. Here i have HTML page in which I have button and also set some custom parameters.

    <script src="//cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/hmac-sha256.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/components/enc-base64-min.js"></script>
    <script language="JavaScript" type="text/javascript" src="https://kjur.github.io/jsrsasign/jsrsasign-latest-all-min.js"></script>

<script type="text/javascript">
    $(function () {
        $("#btnJWTApi").click(function () {
                    // Defining our token parts
                    // You can use one of these, as alg
                    // HS256, HS386, HS512
                    // Always keep type as JWT
                    var header = {
                        "alg": "HS256",
                        "typ": "JWT"
                    };
    
                    var tNow = KJUR.jws.IntDate.getNow();
                    var tEnd = KJUR.jws.IntDate.getNow() + 60 * 5;
                    // dynamically pass these data using a function
                    var data = {
                        "appId": "yourAppId",
                        "iat": tNow,
                        // iat (issued at time) should be set to time when request has been generated
                        "exp": tEnd,
                        // exp (expiration) should not be more than 5 minutes from now, this is to prevent Replay Attacks
                        "method": "TestMethod",
                        "Q": "test",
                        "SecretKey": "MySecretKey"
                    };
                    // Secret key is used for calculating and verifying the signature.
                    // The secret signing key MUST only be accessible by the issuer and the User,
                    // it should not be accessible outside of these two parties.                
                    // Use the Secret you set during user registration from the Plugin
                    var secret = btoa('MySecret ');
    
                    function base64url(source) {
                        // Encode in classical base64
                        encodedSource = CryptoJS.enc.Base64.stringify(source);
                        // Remove padding equal characters
                        encodedSource = encodedSource.replace(/=+$/, '');
                        // Replace characters according to base64url specifications
                        encodedSource = encodedSource.replace(/\+/g, '-');
                        encodedSource = encodedSource.replace(/\//g, '_');
                        return encodedSource;
                    }
    
                    var stringifiedHeader = CryptoJS.enc.Utf8.parse(JSON.stringify(header));
                    var encodedHeader = base64url(stringifiedHeader);
    
                    var stringifiedData = CryptoJS.enc.Utf8.parse(JSON.stringify(data));
                    var encodedData = base64url(stringifiedData);
    
                    var signature = encodedHeader + "." + encodedData;
                    signature = CryptoJS.HmacSHA256(signature, secret);
                    signature = base64url(signature);
    
                    var targetEle = $("#data");
                    $.ajax(
                        {
                            type: "POST",
                            url: "http://localhost:12345/api/v1/MyController/SecureMethod",        
                            data: '{"token":"' + encodedHeader + "." + encodedData + "." + signature + '"}',
                            contentType: "application/json; charset=utf-8",
                            dataType: "json",
                            success: function (data) {
                                targetEle.html("<pre>" + JSON.stringify(data, null, '\t') + "</pre>");
                            },
                            error: function () {
                                alert('error');
                            }
                        });
                });        
            });
    </script>

This call will generate encrypted token which include appId,secret and our payload data with method name.

(Here create one common method, which call first and then according to passing data in a token further method will be call)

This will call your method SecureMethod instead of direct TestMethod. And decrypt token.

public string SecureMethod(dynamic tokenObject)
{
    //save at a time of user registration. 
    string applicationID = appSecret get from database;
    string secretKey = appSecret get from database;
}

var bytes = Encoding.UTF8.GetBytes(secretKey);
                    var secret = Convert.ToBase64String(bytes);
                    var jwtDecryption = JsonWebToken.DecodeToObject(token, secret, true, true);
                    var jsonObj = JObject.FromObject(jwtDecryption);
                    string appId = jsonObj["appId"].Value<string>();
 if (appId.Equals(applicationID)
 {
      object restService = new MyController();
  var method = restService.GetType().GetMethod(jsonObj["method"].ToString(), BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
 }
 if (method != null)
 {    
  var parameters = method.GetParameters().Select(p => Convert.ChangeType(jsonObj[p.Name].ToString(), p.ParameterType)).ToArray();
 object response = method.Invoke(restService, parameters); //your actual method should  
 return new JavaScriptSerializer().Serialize(response);
 }

method.Invoke(restService, parameters); will have method name and parameter so it'll called your method and pass parameters.

public IHttpActionResult TestMethod([FromBody]Response model)
{
   // you will get parameters in a model 

  return Ok();
}

Any suggestion welcome!

Upvotes: 2

Related Questions