I think it is quite important to be proficient in the APIs of the “framework” or “library” that we work on, in addition to the language we use when developing applications. This enables us to easily provide certain requirements or to use the “framework” more effectively. With this approach, I will try to talk about a ITimeLimitedDataProtector API in ASP.NET Core which can be useful for creating secure or limited data models that may be needed for different scenarios.

Temporary data models or “text” expressions that are valid for only a certain period can sometimes be an approach that we need. Links sent for “Email Confirmation” or for resetting passwords during membership transactions may be familiar to many people. Or values such as codes that will be valid for a certain period in “soft-OTP” (One-time password) scenarios or “Bearer” tokens…etc.

Obviously, different methods and approaches are possible for such requirements. Without going into too much detail, I will try to briefly discuss how we can meet such needs in the .NET platform.

As you know, .NET and especially ASP.NET Core guide us with many APIs to meet the security needs of today’s applications. Strong encryption APIs, HTTPS concepts, CORS mechanisms, CRSF prevention, data protection, authentication, authorization, secret usage, and so on…

ITimeLimitedDataProtector

For the requirement I mentioned above, let’s look at the ITimeLimitedDataProtector interface in .NET under the “data protection” namespace. We can have some implementations for data or expressions that will only be valid for a certain period of time with the methods provided by this interface.

To use the methods of this interface, we first need the “Microsoft.AspNetCore.DataProtection.Extensions” package. Generally, this package is a library that exposes “data protection” features in .NET.

To use the “ITimeLimitedDataProtector” interface, we first need to create a “DataProtectionProvider”, and then define a protector that will protect our data with this “provider”.

var timeLimitedDataProtector = DataProtectionProvider.Create("SomeApplication")
    .CreateProtector("SomeApplication.TimeLimitedData")
    .ToTimeLimitedDataProtector();

When you look at the parameters of the methods here, the “string” expressions you see are important; they can be thought of as a kind of labeling for the created provider and DataProtectors. According to this labeling, the purpose and scope of data security are specified. These expressions are used in the creation of the keys that will be used to protect the data. Thus, a provider created with DataProtectionProvider.Create(“abc”) cannot access the expressions that ensure the security of a provider created in the form of DataProtectionProvider.Create(“xyz”).

When you look at the parameters of the DataProtectionProvider.Create() method, you can see that you can set some properties for protecting the data. You can specify a directory where the keys for data protection will be stored or that the keys will be encrypted with an additional certificate using X509Certificate2. I won’t go into too much detail about these, but what I want to emphasize here is that it is possible to customize data protection methods and change protection approaches with parameters.

In this way, we protect the expression we want to protect through the timeLimitedDataProtector variable we created by specifying a time interval with the Protect() method.

ProtectedData = timeLimitedDataProtector.Protect(plaintext: "HelloWorld"
                    , lifetime: TimeSpan.FromSeconds(LifeTime));

With the above expression, we are encrypting, hashing, and protecting the phrase “Hello World”. Our ProtectedData property becomes a structure similar to the following, which is valid for 20 seconds.

Time limit

We can specify any time duration in the form of TimeSpan with the lifetime parameter of the Protect() method, of course.

After protecting the encrypted and hashed expression, we can access the “Hello World” expression again by opening it with the Unprotect() method within 20 seconds as in this example. However, it is not possible to access this value after 20 seconds, and the data we protected loses its validity.

string data = timeLimitedDataProtector.Unprotect(protectedData);

It is not recommended to use data protection for a long or indefinite period of time with this API. The reason is the risk of maintaining the continuity of the keys used for encrypting and hashing the data when it is protected. If there are expressions that need to be kept under protection for a long time, it is possible to proceed with different methods, or different developments can be made according to our own needs using the interfaces provided by this API.

An important point is that only “text” expressions can be protected. Therefore, it is possible to protect slightly more complex data by “serializing” it (for example, using JsonSerializer).

To see the complete picture more clearly, let’s look at the below code of a Razor page model from an ASP.NET Core application as an example.

namespace SomeApplication.Pages
{
    using Microsoft.AspNetCore.DataProtection;
    using Microsoft.AspNetCore.Mvc.RazorPages;
    using Microsoft.Extensions.Logging;
    using System;
    using System.Text.Json;
 
 
    public class IndexModel : PageModel
    {
        private readonly ILogger<IndexModel> _logger;
 
        public string ProtectedData { get; private set; }
        public string Data { get; private set; }
        public int LifeTime { get; private set; } = 300;
        public string Error { get; private set; }
 
 
        public IndexModel(ILogger<IndexModel> logger)
        {
            _logger = logger;
        }
 
        public void OnGet(string protectedData)
        {
            var timeLimitedDataProtector = DataProtectionProvider.Create("SomeApplication")
                .CreateProtector("SomeApplication.TimeLimitedData")
                .ToTimeLimitedDataProtector();
 
            //prtecteddata variable is empty in URL
            if (string.IsNullOrEmpty(protectedData))
            {
                //Let's have a simple data model as example
                var data = new SomeDataModel
                {
                    Name = "Arda Cetinkaya",
                    EMail = "somemail@mail.com",
                    SomeDate = DateTimeOffset.Now
                };
 
                //Let's serialize this simple data model
                string jsonString = JsonSerializer.Serialize(data, new JsonSerializerOptions
                {
                    WriteIndented = true
                });
 
                Data = jsonString;
 
                //Now let's protec the simple data model
                ProtectedData = timeLimitedDataProtector.Protect(plaintext: jsonString
                    , lifetime: TimeSpan.FromSeconds(LifeTime));
            }
            else
            {
                //When URL have some variable value as ?protecdata=a412Fe12dada...
                try
                {
                    //Unprotect the protected value
                    string data = timeLimitedDataProtector.Unprotect(protectedData);
                    Data = "Data is valid";
                }
                catch (Exception ex)
                {
                    Error = ex.Message;
 
                }
 
            }
        }
    }
 
    public class SomeDataModel
    {
        public string Name { get; set; }
        public string EMail { get; set; }
        public DateTimeOffset SomeDate { get; set; }
    }
}

In the example above, we are protecting a JSON expression for 20 seconds and associating it with a link. The link will be valid for 20 seconds and the value we have protected will be valid as well. However, after 20 seconds, the protected data will expire and lose its validity.

This simple and quick writing, after a long break, will hopefully benefit me and open a door for you to clear up some question marks and provide you with some benefits in your various solutions. See you in the next article.

I have written this post and publish as Turkish before. This is english translated version of that post.