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 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 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)))); }
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); }
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 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 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); }
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); }
/// <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)); }
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); } }
public async Task NullToken() => await Assert.ThrowsAsync <ArgumentNullException>(() => JsonWebSignature.VerifySignedTokenAsync(null, BuildOptions()));
public async Task EmptyToken() => await Assert.ThrowsAsync <ArgumentException>(() => JsonWebSignature.VerifySignedTokenAsync("", BuildOptions()));
public async Task ValidES256Signature() => Assert.NotNull(await JsonWebSignature.VerifySignedTokenAsync( FakeCertificateCache.Es256ForIap, BuildOptions(new MockClock(FakeCertificateCache.ValidEs256ForIap))));
public async Task TwoPartToken() => await Assert.ThrowsAsync <InvalidJwtException>(() => JsonWebSignature.VerifySignedTokenAsync("header.payload", BuildOptions()));
public async Task ValidRS256Signature() => Assert.NotNull(await JsonWebSignature.VerifySignedTokenAsync( FakeCertificateCache.JwtGoogleSigned, BuildOptions()));