using JWT; using JWT.Algorithms; using JWT.Builder; using JWT.Serializers; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; using System.Security.Claims; using System.Text; using System.Threading.Tasks; namespace Tango.Web.Security { public class WebToken { public DateTime Issued { get; protected set; } public DateTime? Expiration { get; protected set; } public String AccessToken { get; protected set; } public String RefreshToken { get; protected set; } public WebToken() { } public static WebToken CreateNew(String secret, DateTime? expiration = null) { DateTime issued = DateTime.UtcNow; var builder = new JwtBuilder() .WithAlgorithm(new HMACSHA256Algorithm()) .WithSecret(secret) .IssuedAt(issued); if (expiration != null) { builder = builder.ExpirationTime(expiration.Value); } String refreshToken = Guid.NewGuid().ToString(); builder = builder.AddClaim("object", null); builder = builder.AddClaim("refresh-token", refreshToken); return new WebToken() { AccessToken = builder.Build(), RefreshToken = refreshToken, Expiration = expiration, Issued = issued, }; } public static void Validate(String secret, String token) { var json = new JwtBuilder() .WithSecret(secret) .MustVerifySignature() .Decode(token); } public void Validate(String secret) { var json = new JwtBuilder() .WithSecret(secret) .MustVerifySignature() .Decode(AccessToken); } public WebToken Renew(String secret) { var newToken = CreateNew(secret, DateTime.UtcNow.Add(Expiration.Value - Issued)); newToken.RefreshToken = RefreshToken; return newToken; } public static WebToken FromToken(String token) { WebToken webToken = new WebToken(); var payload = new JwtBuilder() .WithValidator(null) .Decode>(token); webToken.AccessToken = token; if (payload.ContainsKey("exp")) { long exp = long.Parse(payload["exp"].ToString()); webToken.Expiration = ConvertEpochToDateTime(exp); } if (payload.ContainsKey("iat")) { long iat = long.Parse(payload["iat"].ToString()); webToken.Issued = ConvertEpochToDateTime(iat); } if (payload.ContainsKey("refresh-token")) { webToken.RefreshToken = payload["refresh-token"].ToString(); } return webToken; } protected static DateTime ConvertEpochToDateTime(long seconds) { var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); return epoch.AddSeconds(seconds); } } public class WebToken : WebToken where T : class { public T Object { get; protected set; } private WebToken() { } public static WebToken CreateNew(String secret, T obj = null, DateTime? expiration = null) { DateTime issued = DateTime.UtcNow; var builder = new JwtBuilder() .WithAlgorithm(new HMACSHA256Algorithm()) .WithSecret(secret) .IssuedAt(issued); if (expiration != null) { builder = builder.ExpirationTime(expiration.Value); } String refreshToken = Guid.NewGuid().ToString(); builder = builder.AddClaim("object", obj); builder = builder.AddClaim("refresh-token", refreshToken); return new WebToken() { AccessToken = builder.Build(), RefreshToken = refreshToken, Expiration = expiration, Issued = issued, Object = obj, }; } public static new WebToken FromToken(String token) { WebToken webToken = new WebToken(); var payload = new JwtBuilder() .WithValidator(null) .Decode>(token); webToken.AccessToken = token; if (payload.ContainsKey("exp")) { long exp = long.Parse(payload["exp"].ToString()); webToken.Expiration = ConvertEpochToDateTime(exp); } if (payload.ContainsKey("iat")) { long iat = long.Parse(payload["iat"].ToString()); webToken.Issued = ConvertEpochToDateTime(iat); } if (payload.ContainsKey("refresh-token")) { webToken.RefreshToken = payload["refresh-token"].ToString(); } webToken.Object = JsonConvert.DeserializeObject(payload["object"].ToString()); return webToken; } public new WebToken Renew(String secret) { var newToken = WebToken.CreateNew(secret, Object, DateTime.UtcNow.Add(Expiration.Value - Issued)); newToken.RefreshToken = RefreshToken; return newToken; } } }