public override SecurityToken CreateToken(SecurityTokenDescriptor descriptor)
        {
            var jwt = new JsonWebToken();

            if (descriptor.SigningCredentials == null)
            {
                jwt.Header.SignatureAlgorithm = JwtConstants.SignatureAlgorithms.None;
            }
            else
            {
                var algorithm = ParseSigningCredentials(descriptor.SigningCredentials);

                jwt.Header.SigningCredentials = descriptor.SigningCredentials;
                jwt.Header.SignatureAlgorithm = algorithm;
            }

            if (!string.IsNullOrWhiteSpace(descriptor.TokenIssuerName))
            {
                jwt.Issuer = descriptor.TokenIssuerName;
            }

            if (descriptor.Lifetime != null)
            {
                jwt.ExpirationTime = descriptor.Lifetime.Expires.Value.ToEpochTime();
            }

            if (!string.IsNullOrWhiteSpace(descriptor.AppliesToAddress))
            {
                jwt.Audience = new Uri(descriptor.AppliesToAddress);
            }

            if (descriptor.Subject != null)
            {
                foreach (var claim in descriptor.Subject.Claims)
                {
                    jwt.AddClaim(claim.Type, claim.Value);
                }
            }

            return jwt;
        }
        protected virtual void VerifySignature(JsonWebToken jwt, SecurityKey signingKey)
        {
            var key = signingKey as InMemorySymmetricSecurityKey;
            if (key == null)
            {
                throw new SecurityTokenValidationException("Unsupported signing key.");
            }

            string verifySignature;
            using (var algorithm = key.GetKeyedHashAlgorithm(ValidateHmacAlgorithm(key.KeySize, jwt.Header.SignatureAlgorithm)))
            {
                verifySignature = Base64Url.Encode(algorithm.ComputeHash(Encoding.UTF8.GetBytes(jwt.UnsignedToken)));
            }

            if (!(ObfuscatingComparer.IsEqual(verifySignature, jwt.Signature)))
            {
                throw new SecurityTokenValidationException("Invalid signature.");
            }
        }
        protected virtual ClaimsIdentity CreateClaimsIdentity(JsonWebToken jwt)
        {
            var claims = new List<Claim>();

            foreach (var item in jwt.Claims)
            {
                if (item.Value.Contains(','))
                {
                    var items = item.Value.Split(',');
                    foreach (var part in items)
                    {
                        claims.Add(new Claim(item.Key, part, ClaimValueTypes.String, jwt.Issuer));
                    }
                }
                else
                {
                    claims.Add(new Claim(item.Key, item.Value, ClaimValueTypes.String, jwt.Issuer));
                }
            }

            //var claims = new List<Claim>(
            //    from c in jwt.Claims
            //    select new Claim(c.Type, c.Value, c.ValueType, jwt.Issuer));

            if (!string.IsNullOrWhiteSpace(jwt.Principal))
            {
                claims.Add(new Claim("prn", jwt.Principal, ClaimValueTypes.String, jwt.Issuer));
            }

            if (jwt.IssuedAt.HasValue)
            {
                claims.Add(new Claim("iat", jwt.IssuedAt.Value.ToString(), ClaimValueTypes.String, jwt.Issuer));
            }

            return new ClaimsIdentity(claims, "JWT");
        }
        protected virtual void ReadHeader(string header, JsonWebToken jwt)
        {
            var json = JObject.Load(new JsonTextReader(new StringReader(header)));

            var typ = json[JwtConstants.Header.Type];
            if (typ != null && !string.IsNullOrWhiteSpace(typ.ToString()))
            {
                jwt.Header.Type = typ.ToString();
            }

            var alg = json[JwtConstants.Header.Algorithm];
            if (alg == null || string.IsNullOrEmpty(alg.ToString()))
            {
                throw new SecurityTokenException("Algorithm header is missing.");
            }
            jwt.Header.SignatureAlgorithm = alg.ToString();
        }
        protected virtual void ReadClaims(string claims, JsonWebToken jwt)
        {
            var json = JObject.Load(new JsonTextReader(new StringReader(claims)));

            foreach (var item in json)
            {
                switch (item.Key)
                {
                    case JwtConstants.Claims.Audience:
                        jwt.Audience = new Uri(item.Value.ToString());
                        break;
                    case JwtConstants.Claims.ExpirationTime:
                        jwt.ExpirationTime = long.Parse(item.Value.ToString());
                        break;
                    case JwtConstants.Claims.IssuedAt:
                        jwt.IssuedAt = long.Parse(item.Value.ToString());
                        break;
                    case JwtConstants.Claims.Issuer:
                        jwt.Issuer = item.Value.ToString();
                        break;
                    case JwtConstants.Claims.NotBefore:
                        jwt.NotBefore = long.Parse(item.Value.ToString());
                        break;
                    case JwtConstants.Claims.Principal:
                        jwt.Principal = item.Value.ToString();
                        break;
                    default:
                        jwt.Claims.Add(item.Key, item.Value.ToString());
                        break;
                }
            }
        }
        public override SecurityToken ReadToken(string tokenString)
        {
            if (string.IsNullOrWhiteSpace(tokenString))
            {
                throw new ArgumentNullException("tokenString");
            }
          
            var jwt = new JsonWebToken();

            var parts = tokenString.Split('.');
            if (parts.Length < 2)
            {
                tokenString = Encoding.UTF8.GetString(Base64Url.Decode(tokenString));
                parts = tokenString.Split('.');
            }
            if (parts.Length < 2)
            {
                throw new SecurityTokenException("Malformed token");
            }

            var encodedHeader = parts[0];
            var encodedClaims = parts[1];

            ReadHeader(Encoding.UTF8.GetString(Base64Url.Decode(encodedHeader)), jwt);

            string signature = string.Empty;
            if (jwt.Header.SignatureAlgorithm != JwtConstants.SignatureAlgorithms.None)
            {
                if (parts.Length != 3)
                {
                    throw new SecurityTokenException("Signature is missing");
                }

                signature = parts[2];
            }

            jwt.UnsignedToken = string.Format("{0}.{1}", encodedHeader, encodedClaims);
            jwt.Signature = signature;

            ReadClaims(Encoding.UTF8.GetString(Base64Url.Decode(encodedClaims)), jwt);

            return jwt;
        }
 protected virtual void AddUserClaims(JsonWebToken jwt, JsonTextWriter writer)
 {
     foreach (var claim in jwt.Claims)
     {
         writer.WritePropertyName(claim.Key);
         writer.WriteValue(claim.Value);
     }
 }
        protected virtual void AddReservedClaims(JsonWebToken jwt, JsonTextWriter writer)
        {
            // exp
            if (jwt.ExpirationTime.HasValue)
            {
                writer.WritePropertyName(JwtConstants.Claims.ExpirationTime);
                writer.WriteValue(jwt.ExpirationTime.Value);
            }

            // nbf
            if (jwt.NotBefore.HasValue)
            {
                writer.WritePropertyName(JwtConstants.Claims.NotBefore);
                writer.WriteValue(jwt.NotBefore.Value);
            }

            // iat
            if (jwt.IssuedAt.HasValue)
            {
                writer.WritePropertyName(JwtConstants.Claims.IssuedAt);
                writer.WriteValue(jwt.IssuedAt.Value);
            }

            // iss
            if (!string.IsNullOrWhiteSpace(jwt.Issuer))
            {
                writer.WritePropertyName(JwtConstants.Claims.Issuer);
                writer.WriteValue(jwt.Issuer);
            }

            // aud
            if (jwt.Audience != null)
            {
                writer.WritePropertyName(JwtConstants.Claims.Audience);
                writer.WriteValue(jwt.Audience.AbsoluteUri);
            }

            // prn
            if (!string.IsNullOrWhiteSpace(jwt.Principal))
            {
                writer.WritePropertyName(JwtConstants.Claims.Principal);
                writer.WriteValue(jwt.Principal);
            }

            // jti
            if (!string.IsNullOrWhiteSpace(jwt.JwtId))
            {
                writer.WritePropertyName(JwtConstants.Claims.Id);
                writer.WriteValue(jwt.JwtId);
            }
        }
        protected virtual string CreateClaimSet(JsonWebToken jwt)
        {
            StringBuilder sb = new StringBuilder();
            StringWriter sw = new StringWriter(sb);

            using (var jsonWriter = new JsonTextWriter(sw))
            {
                jsonWriter.WriteStartObject();

                AddReservedClaims(jwt, jsonWriter);
                AddUserClaims(jwt, jsonWriter);

                jsonWriter.WriteEndObject();
            }

            var json = sb.ToString();
            Debug.WriteLine(json);

            return Base64Url.Encode(Encoding.UTF8.GetBytes(json));
        }
        protected virtual string CreateHeader(JsonWebToken jwt)
        {
            StringBuilder sb = new StringBuilder();
            StringWriter sw = new StringWriter(sb);

            using (JsonWriter jsonWriter = new JsonTextWriter(sw))
            {
                jsonWriter.WriteStartObject();

                jsonWriter.WritePropertyName(JwtConstants.Header.Type);
                jsonWriter.WriteValue(jwt.Header.Type);
                jsonWriter.WritePropertyName(JwtConstants.Header.Algorithm);
                jsonWriter.WriteValue(jwt.Header.SignatureAlgorithm);

                jsonWriter.WriteEndObject();
            }

            var json = sb.ToString();
            Debug.WriteLine(json);

            return Base64Url.Encode(Encoding.UTF8.GetBytes(json));
        }