Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I have a WCF Webservice which checks if the user is valid.

If the user is valid I want to generate a token which expires after 24 hours.

public bool authenticateUserManual(string userName, string password,string language,string token) {     if (Membership.ValidateUser(userName,password))     {         //////////         string token = ????          //////////          return true;     }     else      {         return false;     } }    
like image 962
Eray Geveci Avatar asked Feb 01 '13 10:02

Eray Geveci


People also ask

How do you set a token to expire?

Go to the Settings tab. Under Refresh Token Expiration, enable Absolute Expiration. When enabled, a refresh token will expire based on an absolute lifetime, after which the token can no longer be used. If rotation is enabled, an expiration lifetime must be set.

Do API tokens expire?

Tokens are valid for 30 days from creation or last use, so that the 30 day expiration automatically refreshes with each API call. Tokens that aren't used for 30 days expire. The 30-day period is currently fixed and can't be changed for your organization.

What do I do with expired tokens?

When a token has expired or has been revoked, it can no longer be used to authenticate Git and API requests. It is not possible to restore an expired or revoked token, you or the application will need to create a new token. This article explains the possible reasons your GitHub token might be revoked or expire.

How can handle token expire in Android?

Whenever user's token get expired then request from Android device to your server to obtain new user's token by sending old user's token along with refresh-token . And you can use that new user's token for future. Repeat this whenever user's token get expired.


2 Answers

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.

like image 86
Guffa Avatar answered Oct 14 '22 06:10

Guffa


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

like image 42
Walter Verhoeven Avatar answered Oct 14 '22 06:10

Walter Verhoeven