how to generate a unique token which expires after 24 hours? how to generate a unique token which expires after 24 hours? asp.net asp.net

how to generate a unique token which expires after 24 hours?


There are two possible approaches; either you create a unique value and store somewhere along with the creation time, for example in a database, or you put the creation time inside the token so that you can decode it later and see when it was created.

To create a unique token:

string token = Convert.ToBase64String(Guid.NewGuid().ToByteArray());

Basic example of creating a unique token containing a time stamp:

byte[] time = BitConverter.GetBytes(DateTime.UtcNow.ToBinary());byte[] key = Guid.NewGuid().ToByteArray();string token = Convert.ToBase64String(time.Concat(key).ToArray());

To decode the token to get the creation time:

byte[] data = Convert.FromBase64String(token);DateTime when = DateTime.FromBinary(BitConverter.ToInt64(data, 0));if (when < DateTime.UtcNow.AddHours(-24)) {  // too old}

Note: If you need the token with the time stamp to be secure, you need to encrypt it. Otherwise a user could figure out what it contains and create a false token.


I like Guffa's answer and since I can't comment I will provide the answer Udil's question here.

I needed something similar but I wanted certein logic in my token, I wanted to:

  1. See the expiration of a token
  2. Use a guid to mask validate (global application guid or user guid)
  3. See if the token was provided for the purpose I created it (no reuse..)
  4. See if the user I send the token to is the user that I am validating it for

Now points 1-3 are fixed length so it was easy, here is my code:

Here is my code to generate the token:

public string GenerateToken(string reason, MyUser user){    byte[] _time     = BitConverter.GetBytes(DateTime.UtcNow.ToBinary());    byte[] _key      = Guid.Parse(user.SecurityStamp).ToByteArray();    byte[] _Id       = GetBytes(user.Id.ToString());    byte[] _reason   = GetBytes(reason);    byte[] data       = new byte[_time.Length + _key.Length + _reason.Length+_Id.Length];    System.Buffer.BlockCopy(_time, 0, data, 0, _time.Length);    System.Buffer.BlockCopy(_key , 0, data, _time.Length, _key.Length);    System.Buffer.BlockCopy(_reason, 0, data, _time.Length + _key.Length, _reason.Length);    System.Buffer.BlockCopy(_Id, 0, data, _time.Length + _key.Length + _reason.Length, _Id.Length);    return Convert.ToBase64String(data.ToArray());}

Here is my Code to take the generated token string and validate it:

public TokenValidation ValidateToken(string reason, MyUser user, string token){    var result = new TokenValidation();    byte[] data     = Convert.FromBase64String(token);    byte[] _time     = data.Take(8).ToArray();    byte[] _key      = data.Skip(8).Take(16).ToArray();    byte[] _reason   = data.Skip(24).Take(2).ToArray();    byte[] _Id       = data.Skip(26).ToArray();    DateTime when = DateTime.FromBinary(BitConverter.ToInt64(_time, 0));    if (when < DateTime.UtcNow.AddHours(-24))    {        result.Errors.Add( TokenValidationStatus.Expired);    }        Guid gKey = new Guid(_key);    if (gKey.ToString() != user.SecurityStamp)    {        result.Errors.Add(TokenValidationStatus.WrongGuid);    }    if (reason != GetString(_reason))    {        result.Errors.Add(TokenValidationStatus.WrongPurpose);    }    if (user.Id.ToString() != GetString(_Id))    {        result.Errors.Add(TokenValidationStatus.WrongUser);    }        return result;}private static string GetString(byte[] reason) => Encoding.ASCII.GetString(reason);private static byte[] GetBytes(string reason) => Encoding.ASCII.GetBytes(reason);

The TokenValidation class looks like this:

public class TokenValidation{    public bool Validated { get { return Errors.Count == 0; } }    public readonly List<TokenValidationStatus> Errors = new List<TokenValidationStatus>();}public enum TokenValidationStatus{    Expired,    WrongUser,    WrongPurpose,    WrongGuid}

Now I have an easy way to validate a token, no Need to Keep it in a list for 24 hours or so.Here is my Good-Case Unit test:

private const string ResetPasswordTokenPurpose = "RP";private const string ConfirmEmailTokenPurpose  = "EC";//change here change bit length for reason  section (2 per char)[TestMethod]public void GenerateTokenTest(){    MyUser user         = CreateTestUser("name");    user.Id             = 123;    user.SecurityStamp  = Guid.NewGuid().ToString();    var token   = sit.GenerateToken(ConfirmEmailTokenPurpose, user);    var validation    = sit.ValidateToken(ConfirmEmailTokenPurpose, user, token);    Assert.IsTrue(validation.Validated,"Token validated for user 123");}

One can adapt the code for other business cases easely.

Happy Coding

Walter


Use Dictionary<string, DateTime> to store token with timestamp:

static Dictionary<string, DateTime> dic = new Dictionary<string, DateTime>();

Add token with timestamp whenever you create new token:

dic.Add("yourToken", DateTime.Now);

There is a timer running to remove any expired tokens out of dic:

 timer = new Timer(1000*60); //assume run in 1 minute timer.Elapsed += timer_Elapsed; static void timer_Elapsed(object sender, ElapsedEventArgs e)    {        var expiredTokens = dic.Where(p => p.Value.AddDays(1) <= DateTime.Now)                              .Select(p => p.Key);        foreach (var key in expiredTokens)            dic.Remove(key);    }

So, when you authenticate token, just check whether token exists in dic or not.