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; } }
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.
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.
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.
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.
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:
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With