public ISimpleWebToken CreateToken(
            string issuer, string audience, DateTime expiryTime, string signingKey,
            IEnumerable <KeyValuePair <string, string> > values = null)
        {
            if (string.IsNullOrEmpty(issuer))
            {
                throw new ArgumentNullException("issuer");
            }
            if (string.IsNullOrEmpty(audience))
            {
                throw new ArgumentNullException("audience");
            }
            if (string.IsNullOrEmpty(signingKey))
            {
                throw new ArgumentNullException("signingKey");
            }

            if (expiryTime.Kind != DateTimeKind.Utc)
            {
                throw new ArgumentOutOfRangeException("expiryTime", "Expiry time must be in UTC.");
            }
            if (expiryTime < _swtBaseTime)
            {
                throw new ArgumentOutOfRangeException("expiryTime", "Expiry time must be after 1970.");
            }
            var signingKeyBytes = Convert.FromBase64String(signingKey);

            if (signingKeyBytes.Length != 32)
            {
                throw new ArgumentOutOfRangeException("signingKey", "Signing key must be 32 bytes.");
            }

            var token = new SimpleWebToken
            {
                Issuer     = issuer,
                Audience   = audience,
                ExpiresOn  = expiryTime,
                Properties = new Dictionary <string, string>()
            };

            var sb = new StringBuilder();

            if (values != null)
            {
                foreach (var item in values)
                {
                    token.Properties.Add(item.Key, item.Value);
                    sb.AppendFormat("{0}={1}&", WebUtility.UrlEncode(item.Key), WebUtility.UrlEncode(item.Value));
                }
            }

            sb.AppendFormat("{0}={1}&", SimpleWebTokenConstants.Audience, WebUtility.UrlEncode(audience));
            sb.AppendFormat("{0}={1}&", SimpleWebTokenConstants.ExpiresOn, GetSwtTime(expiryTime));
            sb.AppendFormat("{0}={1}", SimpleWebTokenConstants.Issuer, WebUtility.UrlEncode(issuer));
            token.Signature = GenerateSignature(sb.ToString(), signingKeyBytes);
            sb.AppendFormat("&{0}={1}", SimpleWebTokenConstants.Signature, WebUtility.UrlEncode(token.Signature));

            token.RawToken = sb.ToString();
            return(token);
        }
        public ISimpleWebToken CreateTokenFromRaw(string rawToken)
        {
            if (string.IsNullOrEmpty(rawToken))
            {
                throw new ArgumentNullException("rawToken");
            }

            var token = new SimpleWebToken {
                RawToken = rawToken, Properties = new Dictionary <string, string>()
            };

            foreach (var rawNameValue in rawToken.Split(new[] { '&' }, StringSplitOptions.RemoveEmptyEntries))
            {
                var nameValue = rawNameValue.Split('=');

                if (nameValue.Length != 2)
                {
                    throw new FormatException(
                              string.Format(
                                  CultureInfo.InvariantCulture,
                                  "Invalid token contains a name/value pair missing an = character: '{0}'",
                                  rawNameValue));
                }

                var key    = WebUtility.UrlDecode(nameValue[0]);
                var values = WebUtility.UrlDecode(nameValue[1]);

                switch (key)
                {
                case SimpleWebTokenConstants.Issuer:
                    token.Issuer = values;
                    break;

                case SimpleWebTokenConstants.Audience:
                    token.Audience = values;
                    break;

                case SimpleWebTokenConstants.ExpiresOn:
                    token.ExpiresOn = GetTimeAsDateTime(string.IsNullOrEmpty(values) ? "0" : values);
                    break;

                case SimpleWebTokenConstants.Signature:
                    token.Signature = values;
                    break;

                default:
                    token.Properties[key] = values;
                    break;
                }
            }
            return(token);
        }
        public ISimpleWebToken CreateTokenFromRaw(string rawToken)
        {
            if (string.IsNullOrEmpty(rawToken)) throw new ArgumentNullException("rawToken");

            var token = new SimpleWebToken { RawToken = rawToken, Properties = new Dictionary<string, string>() };

            foreach (var rawNameValue in rawToken.Split(new[] { '&' }, StringSplitOptions.RemoveEmptyEntries))
            {
                var nameValue = rawNameValue.Split('=');

                if (nameValue.Length != 2)
                {
                    throw new FormatException(
                        string.Format(
                            CultureInfo.InvariantCulture,
                            "Invalid token contains a name/value pair missing an = character: '{0}'",
                            rawNameValue));
                }

                var key = WebUtility.UrlDecode(nameValue[0]);
                var values = WebUtility.UrlDecode(nameValue[1]);

                switch (key)
                {
                    case SimpleWebTokenConstants.Issuer:
                        token.Issuer = values;
                        break;
                    case SimpleWebTokenConstants.Audience:
                        token.Audience = values;
                        break;
                    case SimpleWebTokenConstants.ExpiresOn:
                        token.ExpiresOn = GetTimeAsDateTime(string.IsNullOrEmpty(values) ? "0" : values);
                        break;
                    case SimpleWebTokenConstants.Signature:
                        token.Signature = values;
                        break;
                    default:
                        token.Properties[key] = values;
                        break;
                }
            }
            return token;
        }
        public ISimpleWebToken CreateToken(
            string issuer, string audience, DateTime expiryTime, string signingKey,
            IEnumerable<KeyValuePair<string, string>> values = null)
        {
            if (string.IsNullOrEmpty(issuer)) throw new ArgumentNullException("issuer");
            if (string.IsNullOrEmpty(audience)) throw new ArgumentNullException("audience");
            if (string.IsNullOrEmpty(signingKey)) throw new ArgumentNullException("signingKey");

            if (expiryTime.Kind != DateTimeKind.Utc) throw new ArgumentOutOfRangeException("expiryTime", "Expiry time must be in UTC.");
            if (expiryTime < _swtBaseTime) throw new ArgumentOutOfRangeException("expiryTime", "Expiry time must be after 1970.");
            var signingKeyBytes = Convert.FromBase64String(signingKey);
            if (signingKeyBytes.Length != 32) throw new ArgumentOutOfRangeException("signingKey", "Signing key must be 32 bytes.");

            var token = new SimpleWebToken
            {
                Issuer = issuer,
                Audience = audience,
                ExpiresOn = expiryTime,
                Properties = new Dictionary<string, string>()
            };

            var sb = new StringBuilder();
            if (values != null)
            {
                foreach (var item in values)
                {
                    token.Properties.Add(item.Key, item.Value);
                    sb.AppendFormat("{0}={1}&", WebUtility.UrlEncode(item.Key), WebUtility.UrlEncode(item.Value));
                }
            }

            sb.AppendFormat("{0}={1}&", SimpleWebTokenConstants.Audience, WebUtility.UrlEncode(audience));
            sb.AppendFormat("{0}={1}&", SimpleWebTokenConstants.ExpiresOn, GetSwtTime(expiryTime));
            sb.AppendFormat("{0}={1}", SimpleWebTokenConstants.Issuer, WebUtility.UrlEncode(issuer));
            token.Signature = GenerateSignature(sb.ToString(), signingKeyBytes);
            sb.AppendFormat("&{0}={1}", SimpleWebTokenConstants.Signature, WebUtility.UrlEncode(token.Signature));

            token.RawToken = sb.ToString();
            return token;
        }