public async Task ValidES256Signature_Unsupported()
        {
            var ex = await Assert.ThrowsAsync <InvalidOperationException>(() => JsonWebSignature.VerifySignedTokenAsync(
                                                                              FakeCertificateCache.Es256ForIap, BuildOptions(new MockClock(FakeCertificateCache.ValidEs256ForIap))));

            Assert.Equal("ES256 signed token verification is not supported in this platform.", ex.Message);
        }
        public async Task ValidAudience()
        {
            var options = BuildOptions(trustedAudiences: new string[] { "233772281425-ab2mcbiqmv8kh0mdnqsrkrod97qk37h0.apps.googleusercontent.com" });
            var payload = await JsonWebSignature.VerifySignedTokenAsync(FakeCertificateCache.JwtGoogleSigned, options);

            Assert.NotNull(payload);
        }
Esempio n. 3
0
        public void POST_Nonce_Empty()
        {
            AcmeResponse response = null;

            using var provider = Application.CreateProvider();
            IAcmeController controller = (IAcmeController)provider.GetService(typeof(IAcmeController));

            var accountKey = RSA.Create(2048);
            var token      = new JsonWebSignature();

            token.SetProtected(new JsonWebSignatureProtected
            {
                Url       = $"{Application.BaseAddress}new-acct",
                Algorithm = AlgorithmsEnum.RS256,
                Key       = new JsonWebKey(accountKey),
            });
            token.Sign(accountKey);

            response = controller.CreateAccount(new AcmeRequest
            {
                Path   = $"{Application.BaseAddress}new-acct",
                Method = "POST",
                Token  = token,
            });

            Assert.Equal(400, response.StatusCode);

            var content = response.GetContent <Protocol.Error>();

            Assert.Equal(Protocol.ErrorType.Malformed, content.Type);
            Assert.NotNull(content.Detail);
        }
Esempio n. 4
0
        /// <summary>
        /// Rotates the current Public key that is associated with this Account by the target ACME CA with a new Public key.
        /// </summary>
        /// <see cref="https://tools.ietf.org/html/draft-ietf-acme-acme-18#section-7.3.5"/>
        public async Task <AcmeResponse <Protocol.Account> > AccountChangeKeyAsync(AsymmetricAlgorithm keyNew)
        {
            Logger.Info("Changing an ACME account key. Params:{@params}", keyNew);

            var jws    = new JsonWebSignature();
            var jwk    = new JsonWebKey(Key);
            var jwkNew = new JsonWebKey(keyNew);

            jws.SetPayload(new Protocol.Messages.ChangeKey
            {
                Account = Location,
                Key     = jwk,
            });
            jws.SetProtected(new JsonWebSignatureProtected
            {
                Algorithm = AlgorithmsEnum.RS256,
                Url       = Directory.KeyChange,
                Key       = jwkNew,
            });
            jws.Sign(keyNew);

            var response = await Request(GetType(typeof(Protocol.Account)), Directory.KeyChange,
                                         new RequestParams
            {
                Method  = HttpMethod.Post,
                Payload = jws
            });

            Key = keyNew;

            return(response);
        }
        public async Task OidcTokenProvider_ComputeCredential()
        {
            // This test only executes on GCE so we are certain to have a ComputeCredential.
            GoogleCredential credential = GoogleCredential.FromComputeCredential();

            OidcToken token = await credential.GetOidcTokenAsync(
                OidcTokenOptions.FromTargetAudience("https://this.is.a.test"));

            // Check an access token (really id_token) is available.
            Assert.NotNull(await token.GetAccessTokenAsync());
            // If IdToken is set and AccessToken is not, AccessToken is set to
            // IdToken, so we can always check here that AccessToken is not null.
            Assert.NotNull(token.TokenResponse.AccessToken);
            // The enpoint does not send an expiry, bu we set it to the id_token
            // expiry.
            Assert.NotNull(token.TokenResponse.ExpiresInSeconds);

            var verificationOptions = new SignedTokenVerificationOptions();

            verificationOptions.TrustedAudiences.Add("https://this.is.a.test");

            var payload = await JsonWebSignature.VerifySignedTokenAsync(await token.GetAccessTokenAsync(), verificationOptions);

            Assert.NotNull(payload);
            Assert.Contains("https://this.is.a.test", payload.AudienceAsList);
        }
        public async Task Validate_Signature_Time()
        {
            var clockInvalid1 = new MockClock(FakeCertificateCache.BeforeValidJwtGoogleSigned);
            var clockValid1   = new MockClock(FakeCertificateCache.ValidJwtGoogleSigned);
            var clockInvalid2 = new MockClock(FakeCertificateCache.AfterValidJwtGoogleSigned);

            // Test with no tolerance
            Assert.NotNull(await JsonWebSignature.VerifySignedTokenAsync(FakeCertificateCache.JwtGoogleSigned, BuildOptions(clockValid1)));

            var ex1 = await Assert.ThrowsAsync <InvalidJwtException>(() =>
                                                                     JsonWebSignature.VerifySignedTokenAsync(FakeCertificateCache.JwtGoogleSigned, BuildOptions(clockInvalid1)));

            Assert.Equal("JWT is not yet valid.", ex1.Message);

            var ex2 = await Assert.ThrowsAsync <InvalidJwtException>(() =>
                                                                     JsonWebSignature.VerifySignedTokenAsync(FakeCertificateCache.JwtGoogleSigned, BuildOptions(clockInvalid2)));

            Assert.Equal("JWT has expired.", ex2.Message);

            // Test with tolerance
            await Assert.ThrowsAsync <InvalidJwtException>(() =>
                                                           JsonWebSignature.VerifySignedTokenAsync(FakeCertificateCache.JwtGoogleSigned, BuildOptions(clockInvalid1, clockTolerance: TimeSpan.FromSeconds(109))));

            Assert.NotNull(await JsonWebSignature.VerifySignedTokenAsync(FakeCertificateCache.JwtGoogleSigned, BuildOptions(clockInvalid1, clockTolerance: TimeSpan.FromSeconds(111))));
            Assert.NotNull(await JsonWebSignature.VerifySignedTokenAsync(FakeCertificateCache.JwtGoogleSigned, BuildOptions(clockInvalid2, clockTolerance: TimeSpan.FromSeconds(11))));
            await Assert.ThrowsAsync <InvalidJwtException>(() =>
                                                           JsonWebSignature.VerifySignedTokenAsync(FakeCertificateCache.JwtGoogleSigned, BuildOptions(clockInvalid2, clockTolerance: TimeSpan.FromSeconds(9))));
        }
Esempio n. 7
0
        /// <summary>
        /// Account create with external account binding.
        /// </summary>
        /// <see cref="https://tools.ietf.org/html/draft-ietf-acme-acme-12#section-7.3.5"/>
        public async Task <AcmeResponse <Protocol.Account> > AccountCreateAsync(Protocol.Messages.NewAccount account, string kid, string keyMac)
        {
            Logger.Info("Creating a new ACME account with external account binding. Params:{@params}", new
            {
                Account = account,
                KeyId   = kid,
                KeyMac  = keyMac,
            });

            var jws = new JsonWebSignature();

            jws.SetProtected(new JsonWebSignatureProtected
            {
                Algorithm = AlgorithmsEnum.HS256,
                KeyID     = kid,
                Url       = Directory.NewAccount,
            });

            jws.SetPayload(new JsonWebKey(Key));

            var key = HMAC.Create("HMACSHA256");

            key.Key = Base64Url.Decode(keyMac);

            jws.Sign(key);

            account.ExternalAccountBinding = jws;

            return(await AccountCreateAsync(account));
        }
        public async Task InvalidAudience()
        {
            var options = BuildOptions(trustedAudiences: new string[] { "audience1", "audience2" });
            var ex      = await Assert.ThrowsAsync <InvalidJwtException>(() =>
                                                                         JsonWebSignature.VerifySignedTokenAsync(FakeCertificateCache.JwtGoogleSigned, options));

            Assert.Equal("JWT contains untrusted 'aud' claim.", ex.Message);
        }
        public async Task ValidRS256Signature_CustomPayload()
        {
            var payload = await JsonWebSignature.VerifySignedTokenAsync <CustomPayload>(FakeCertificateCache.JwtGoogleSigned, BuildOptions());

            Assert.NotNull(payload);
            Assert.NotNull(payload.AuthorizedParty);
            Assert.NotEmpty(payload.AuthorizedParty);
        }
        public async Task InvalidIssuer()
        {
            var options = BuildOptions(trustedIssuers: new string[] { "issuer1", "issuer2" });
            var ex      = await Assert.ThrowsAsync <InvalidJwtException>(() =>
                                                                         JsonWebSignature.VerifySignedTokenAsync(FakeCertificateCache.JwtGoogleSigned, options));

            Assert.Equal("JWT issuer incorrect. Must be one of: 'issuer1', 'issuer2'", ex.Message);
        }
        public async Task WrongAlgorithm()
        {
            string jwt = $"{UrlSafeBase64Encode("{\"alg\":\"HS256\"}")}.{UrlSafeBase64Encode("{}")}.";
            var    ex  = await Assert.ThrowsAsync <InvalidJwtException>(() =>
                                                                        JsonWebSignature.VerifySignedTokenAsync(jwt, BuildOptions()));

            Assert.Equal("Signing algorithm must be either RS256 or ES256.", ex.Message);
        }
Esempio n. 12
0
        public ActionResult PostOrders([FromBody] JsonWebSignature token)
        {
            var response = Controller.PostOrders(GetAcmeRequest(token));

            ProcessOrders(response);

            return(CreateActionResult(response));
        }
Esempio n. 13
0
 private AcmeRequest GetAcmeRequest(JsonWebSignature token)
 {
     return(new AcmeRequest(token)
     {
         Method = Request.Method,
         Query = GetQuery(),
         Path = UriHelper.GetDisplayUrl(Request),
     });
 }
Esempio n. 14
0
 protected AcmeRequest GetAcmeRequest(JsonWebSignature token)
 {
     return(new AcmeRequest(token)
     {
         Method = Request.Method.Method,
         Query = GetQuery(),
         Path = Request.RequestUri.ToString(),
     });
 }
        public async Task InvalidES256Signature_Unsupported()
        {
            // Lets just change the last character of the signed token to break the signature.
            // But Headers and Payload are still valid so we guarantee that the only
            // failure comes from the signature being invalid.
            // The last character was an A, changing for a 4. If at some point the token used in tests changes
            // and the new token ends in anything but a 4, this test will still be valid. If the new token ends in a 4
            // this test will fail and then we'll have to replace the 4 by an A or any other character.
            var invalidToken = FakeCertificateCache.Es256ForIap.Substring(0, FakeCertificateCache.Es256ForIap.Length - 1) + "4";
            var ex           = await Assert.ThrowsAsync <InvalidOperationException>(() =>
                                                                                    JsonWebSignature.VerifySignedTokenAsync(invalidToken, BuildOptions(new MockClock(FakeCertificateCache.ValidEs256ForIap))));

            Assert.Equal("ES256 signed token verification is not supported in this platform.", ex.Message);
        }
        public async Task InvalidRS256Signature()
        {
            // Lets just change the last character of the Google signed token to break the signature.
            // But Headers and Payload are still valid for a Google token so we guarantee that the only
            // failure comes from the signature being invalid.
            // The last character was a Q, changing for a 4. If at some point the token used in tests changes
            // and the new token ends in anything but a 4, this test will still be valid. If the new token ends in a 4
            // this test will fail and then we'll have to replace the 4 by a Q or any other character.
            var invalidToken = FakeCertificateCache.JwtGoogleSigned.Substring(0, FakeCertificateCache.JwtGoogleSigned.Length - 1) + "4";
            var ex           = await Assert.ThrowsAsync <InvalidJwtException>(() =>
                                                                              JsonWebSignature.VerifySignedTokenAsync(invalidToken, BuildOptions()));

            Assert.Equal("JWT invalid, unable to verify signature.", ex.Message);
        }
Esempio n. 17
0
        public void Account_New_TermsOfService_Enabled_TermsOfServiceAgreed_False()
        {
            AcmeResponse response = null;

            using var provider = Application.CreateProvider(o =>
            {
                o.TermsOfService = "https://some.com/acme/terms.pdf";
            });
            IAcmeController controller = (IAcmeController)provider.GetService(typeof(IAcmeController));

            // Get nonce
            response = controller.GetNonce(new AcmeRequest
            {
                Path   = $"{Application.BaseAddress}new-nonce",
                Method = "HEAD",
            });

            // Create token
            var accountKey = RSA.Create(2048);
            var token      = new JsonWebSignature();

            token.SetProtected(new JsonWebSignatureProtected
            {
                Url       = $"{Application.BaseAddress}new-acct",
                Algorithm = AlgorithmsEnum.RS256,
                Key       = new JsonWebKey(accountKey),
                Nonce     = response.Headers.ReplayNonce,
            });
            token.SetPayload(new NewAccount
            {
                Contacts             = new string[] { "mailto:[email protected]" },
                TermsOfServiceAgreed = false,
            });
            token.Sign(accountKey);

            // Create account
            response = controller.CreateAccount(new AcmeRequest
            {
                Path   = $"{Application.BaseAddress}new-acct",
                Method = "POST",
                Token  = token,
            });

            Assert.Equal(400, response.StatusCode);

            var content = response.GetContent <Protocol.Error>();

            Assert.Equal(Protocol.ErrorType.Malformed, content.Type);
            Assert.NotNull(content.Detail);
        }
Esempio n. 18
0
    /// <summary>
    /// Verifies a signed jwt token and returns its payload.
    /// </summary>
    /// <param name="signedJwt">The token to verify.</param>
    /// <param name="expectedAudience">The audience that the token should be meant for.
    /// Validation will fail if that's not the case.</param>
    /// <param name="cancellationToken">The cancellation token to propagate cancellation requests.</param>
    /// <returns>A task that when completed will have as its result the payload of the verified token.</returns>
    /// <exception cref="InvalidJwtException">If verification failed. The message of the exception will contain
    /// information as to why the token failed.</exception>
    public async Task <JsonWebSignature.Payload> VerifyTokenAsync(
        string signedJwt, string expectedAudience, CancellationToken cancellationToken = default)
    {
        SignedTokenVerificationOptions options = new SignedTokenVerificationOptions
        {
            // Use clock tolerance to account for possible clock differences
            // between the issuer and the verifier.
            IssuedAtClockTolerance = TimeSpan.FromMinutes(1),
            ExpiryClockTolerance   = TimeSpan.FromMinutes(1),
            TrustedAudiences       = { expectedAudience }
        };

        return(await JsonWebSignature.VerifySignedTokenAsync(signedJwt, options, cancellationToken : cancellationToken));
    }
Esempio n. 19
0
        public void Account_New_TermsOfService_Disabled()
        {
            AcmeResponse response = null;

            using var provider = Application.CreateProvider();
            IAcmeController controller = (IAcmeController)provider.GetService(typeof(IAcmeController));

            // Get nonce
            response = controller.GetNonce(new AcmeRequest
            {
                Path   = $"{Application.BaseAddress}new-nonce",
                Method = "HEAD",
            });

            // Create token
            var accountKey = RSA.Create(2048);
            var token      = new JsonWebSignature();

            token.SetProtected(new JsonWebSignatureProtected
            {
                Url       = $"{Application.BaseAddress}new-acct",
                Algorithm = AlgorithmsEnum.RS256,
                Key       = new JsonWebKey(accountKey),
                Nonce     = response.Headers.ReplayNonce,
            });
            token.SetPayload(new NewAccount
            {
                Contacts = new string[] { "mailto:[email protected]" },
            });
            token.Sign(accountKey);

            // Create account
            response = controller.CreateAccount(new AcmeRequest
            {
                Path   = $"{Application.BaseAddress}new-acct",
                Method = "POST",
                Token  = token,
            });

            Assert.Equal(201, response.StatusCode);

            var content = response.GetContent <Protocol.Account>();

            Assert.Single(response.Headers.Link);
            Assert.Equal("https://test.server.com/acme/acct/1", response.Headers.Location);
            Assert.NotNull(content);
            Assert.NotNull(content.Key);
            Assert.Null(content.TermsOfServiceAgreed);
        }
Esempio n. 20
0
        public ActionResult GetCertificate([FromBody] JsonWebSignature token, string id)
        {
            var response = Controller.GetCertificate(GetAcmeRequest(token), id);

            if (response.Content is MediaTypeContent content)
            {
                foreach (var header in response.Headers.AllKeys)
                {
                    Response.Headers.Add(header, response.Headers.Get(header));
                }

                return(new FileStreamResult(content.Content, content.Type));
            }
            else
            {
                return(CreateActionResult(response));
            }
        }
Esempio n. 21
0
        public void POST_Url_WrongTargetUrl()
        {
            /// The value of the "url" header
            /// parameter MUST be a string representing the target URL

            AcmeResponse response = null;

            using var provider = Application.CreateProvider();
            IAcmeController controller = (IAcmeController)provider.GetService(typeof(IAcmeController));

            // Get nonce
            response = controller.GetNonce(new AcmeRequest
            {
                Path   = $"{Application.BaseAddress}new-nonce",
                Method = "HEAD",
            });

            var accountKey = RSA.Create(2048);
            var token      = new JsonWebSignature();

            token.SetProtected(new JsonWebSignatureProtected
            {
                Url       = "https://wrong.com/acme/new-account",
                Nonce     = response.Headers.ReplayNonce,
                Algorithm = AlgorithmsEnum.RS256,
                Key       = new JsonWebKey(accountKey),
            });
            token.Sign(accountKey);

            response = controller.CreateAccount(new AcmeRequest
            {
                Path   = $"{Application.BaseAddress}new-acct",
                Method = "POST",
                Token  = token,
            });

            Assert.Equal(400, response.StatusCode);

            var content = response.GetContent <Protocol.Error>();

            Assert.Equal(Protocol.ErrorType.Malformed, content.Type);
            Assert.NotNull(content.Detail);
        }
Esempio n. 22
0
        /// <inheritdoc/>
        public IExternalAccount Validate(JsonWebKey accountKey, JsonWebSignature token)
        {
            #region Check arguments
            if (accountKey is null)
            {
                throw new ArgumentNullException(nameof(accountKey));
            }
            if (token is null)
            {
                throw new ArgumentNullException(nameof(token));
            }
            #endregion

            var @prtoected = token.GetProtected();

            var eabPayload = token.GetPayload <JsonWebKey>();
            if (!eabPayload.Equals(accountKey))
            {
                throw new MalformedException("Signed content in externalAccountBinding doesn't match to requirement"); // TODO check rfc error
            }

            var externalAccount = GetById(@prtoected.KeyID);
            if (externalAccount.Status != Protocol.ExternalAccountStatus.Pending)
            {
                throw new MalformedException("External account has wrong status"); // TODO check rfc error
            }

            var key = Base64Url.Decode(externalAccount.Key);

            externalAccount.Status = token.Verify(key)
                ? Protocol.ExternalAccountStatus.Valid
                : Protocol.ExternalAccountStatus.Invalid;
            ExternalAccountRepository.Update(externalAccount);

            Logger.Info("External account {id} status updated to {status}", externalAccount.Id, externalAccount.Status);

            return(externalAccount);
        }
Esempio n. 23
0
        public async Task <string> Run(string targetAudience, string credentialsFilePath, string uri)
        {
            ServiceAccountCredential saCredential;

            using (var fs = new FileStream(credentialsFilePath, FileMode.Open, FileAccess.Read))
            {
                saCredential = ServiceAccountCredential.FromServiceAccountData(fs);
            }
            OidcToken oidcToken = await saCredential.GetOidcTokenAsync(OidcTokenOptions.FromTargetAudience(targetAudience).WithTokenFormat(OidcTokenFormat.Standard)).ConfigureAwait(false);

            string token = await oidcToken.GetAccessTokenAsync().ConfigureAwait(false);

            // the following snippet verifies an id token.
            // this step is done on the  receiving end of the oidc endpoint
            // adding this step in here as just as a demo on how to do this
            //var options = SignedTokenVerificationOptions.Default;
            SignedTokenVerificationOptions options = new SignedTokenVerificationOptions
            {
                IssuedAtClockTolerance = TimeSpan.FromMinutes(1),
                ExpiryClockTolerance   = TimeSpan.FromMinutes(1),
                TrustedAudiences       = { targetAudience },
                CertificatesUrl        = "https://www.googleapis.com/oauth2/v3/certs" // default value
            };
            var payload = await JsonWebSignature.VerifySignedTokenAsync(token, options);

            Console.WriteLine("Verified with audience " + payload.Audience);
            // end verification

            // use the token
            using (var httpClient = new HttpClient())
            {
                httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
                string response = await httpClient.GetStringAsync(uri).ConfigureAwait(false);

                Console.WriteLine(response);
                return(response);
            }
        }
Esempio n. 24
0
        public void POST_Nonce_WrongEncoding()
        {
            AcmeResponse response = null;

            using var provider = Application.CreateProvider();
            IAcmeController controller = (IAcmeController)provider.GetService(typeof(IAcmeController));

            var accountKey = RSA.Create(2048);
            var token      = new JsonWebSignature();

            token.SetProtected(new JsonWebSignatureProtected
            {
                Url       = $"{Application.BaseAddress}new-acct",
                Algorithm = AlgorithmsEnum.RS256,
                Key       = new JsonWebKey(accountKey),
                Nonce     = "Wrong encoded nonce"
            });
            token.Sign(accountKey);

            response = controller.CreateAccount(new AcmeRequest
            {
                Path   = $"{Application.BaseAddress}new-acct",
                Method = "POST",
                Token  = token,
            });

            // If the value of a "nonce" header parameter is not valid
            // according to this encoding, then the verifier MUST reject the JWS as
            // malformed.
            Assert.Equal(400, response.StatusCode);

            var content = response.GetContent <Protocol.Error>();

            Assert.Equal(Protocol.ErrorType.Malformed, content.Type);
            Assert.NotNull(content.Detail);
        }
		/// <summary>
		/// Signs JWT token using the private key and returns the serialized assertion.
		/// </summary>
		/// <param name="payload">the JWT payload to sign.</param>
		private string CreateAssertionFromPayload(JsonWebSignature.Payload payload)
		{
			string serializedHeader = CreateSerializedHeader();
			string serializedPayload = NewtonsoftJsonSerializer.Instance.Serialize(payload);

			StringBuilder assertion = new StringBuilder();
			assertion.Append(UrlSafeBase64Encode(serializedHeader))
				.Append(".")
				.Append(UrlSafeBase64Encode(serializedPayload));

			// Sign the header and the payload.
			var hashAlg = new SHA256CryptoServiceProvider();
			byte[] assertionHash = hashAlg.ComputeHash(Encoding.ASCII.GetBytes(assertion.ToString()));

			var signature = UrlSafeBase64Encode(key.SignHash(assertionHash, "2.16.840.1.101.3.4.2.1" /* SHA256 OIG */)); 
			assertion.Append(".").Append(signature);
			return assertion.ToString();
		}
        /// <summary>
        /// Signs JWT token using the private key and returns the serialized assertion.
        /// </summary>
        /// <param name="payload">the JWT payload to sign.</param>
        private string CreateAssertionFromPayload(JsonWebSignature.Payload payload)
        {
            string serializedHeader = CreateSerializedHeader();
            string serializedPayload = NewtonsoftJsonSerializer.Instance.Serialize(payload);

            StringBuilder assertion = new StringBuilder();
            assertion.Append(UrlSafeBase64Encode(serializedHeader))
                .Append(".")
                .Append(UrlSafeBase64Encode(serializedPayload));

            // Sign the header and the payload.
            var hashAlg = SHA256.Create();
            byte[] assertionHash = hashAlg.ComputeHash(Encoding.ASCII.GetBytes(assertion.ToString()));
#if NETSTANDARD
            var sigBytes = key.SignHash(assertionHash, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
#else
            var sigBytes = key.SignHash(assertionHash, Sha256Oig);
#endif
            var signature = UrlSafeBase64Encode(sigBytes);
            assertion.Append(".").Append(signature);
            return assertion.ToString();
        }
 public async Task ValidES256Signature() =>
 Assert.NotNull(await JsonWebSignature.VerifySignedTokenAsync(
                    FakeCertificateCache.Es256ForIap, BuildOptions(new MockClock(FakeCertificateCache.ValidEs256ForIap))));
 public async Task ValidRS256Signature() =>
 Assert.NotNull(await JsonWebSignature.VerifySignedTokenAsync(
                    FakeCertificateCache.JwtGoogleSigned, BuildOptions()));
Esempio n. 29
0
        public ActionResult RevokeCertificate([FromBody] JsonWebSignature token)
        {
            var response = Controller.RevokeCertificate(GetAcmeRequest(token));

            return(CreateActionResult(response));
        }
 public async Task TwoPartToken() =>
 await Assert.ThrowsAsync <InvalidJwtException>(() =>
                                                JsonWebSignature.VerifySignedTokenAsync("header.payload", BuildOptions()));
 public async Task EmptyToken() =>
 await Assert.ThrowsAsync <ArgumentException>(() =>
                                              JsonWebSignature.VerifySignedTokenAsync("", BuildOptions()));
 public async Task NullToken() =>
 await Assert.ThrowsAsync <ArgumentNullException>(() =>
                                                  JsonWebSignature.VerifySignedTokenAsync(null, BuildOptions()));