<commit_before>﻿using Auth0.AuthenticationApi.IntegrationTests.Tokens;
using Auth0.AuthenticationApi.Tokens;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Threading.Tasks;
using Xunit;

namespace Auth0.OidcClient.Core.UnitTests.Tokens
{
    public class IdTokenValidatorUnitTests
    {
        private static readonly DateTime tokensWereValid = new DateTime(2019, 9, 9, 10, 00, 00, DateTimeKind.Utc);
        private static readonly ISignatureVerifier rs256NoSignature = new NoSignatureVerifier(new[] { "RS256" });

        private static readonly IdTokenRequirements defaultReqs =
            new IdTokenRequirements("https://tokens-test.auth0.com/", "tokens-test-123", TimeSpan.FromMinutes(1))
            {
                Nonce = "a1b2c3d4e5",
                MaxAge = TimeSpan.FromSeconds(100)
            };

        private static readonly JsonWebKeySet signingKeys = new JsonWebKeySet("{\"keys\":[{\"alg\":\"RS256\",\"kty\":\"RSA\",\"use\":\"sig\",\"x5c\":[\"<KEY>\"],\"n\":\"<KEY>\",\"e\":\"AQAB\",\"kid\":\"<KEY>\",\"x5t\":\"<KEY>}]}");

        private static readonly IdTokenRequirements signedReqs =
            new IdTokenRequirements("https://auth0-dotnet-integration-tests.auth0.com/", "qmss9A66stPWTOXjR6X1OeA0DLadoNP2", TimeSpan.FromMinutes(1))
            {
                Nonce = "SOrHOau9q0itx4iTF_iX2w"
            };

        private Task ValidateToken(string token, IdTokenRequirements reqs = null, DateTime? when = null, ISignatureVerifier signatureVerifier = null)
        {
            return IdTokenValidator.AssertTokenMeetsRequirements(reqs ?? defaultReqs, token, when ?? tokensWereValid, signatureVerifier ?? rs256NoSignature);
        }

        [Fact]
        public async void ThrowsWhenIdTokenIsNull()
        {
            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken(null));
            Assert.Equal("ID token is required but missing.", ex.Message);
        }

        [Fact]
        public async void ThrowsWhenIdTokenIsEmpty()
        {
            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken(""));
            Assert.Equal("ID token is required but missing.", ex.Message);
        }

        [Fact]
        public async void ThrowsWhenIdTokenIsWhitespace()
        {
            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken("  "));
            Assert.Equal("ID token is required but missing.", ex.Message);
        }

        [Fact]
        public async void ThrowsWhenIdTokenCanNotBeDecoded()
        {
            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken("@#$?Not A Valid Token@#$!"));
            Assert.Equal("ID token could not be decoded.", ex.Message);
        }

        [Fact]
        public async void SucceedsWhenRS256SignatureIsValid()
        {
            var token = "<KEY>";

            var rs256Verifier = new AsymmetricSignatureVerifier(signingKeys.Keys);

            await ValidateToken(token, signedReqs, when: new DateTime(2019, 11, 1, 11, 00, 00), signatureVerifier: rs256Verifier);
        }

        [Fact]
        public async void SucceedsWhenHS256SignatureIsValid()
        {
            var token = "<KEY>";

            var hs256Verifier = SymmetricSignatureVerifier.FromClientSecret("<KEY>");

            await ValidateToken(token, signedReqs, when: new DateTime(2019, 11, 1, 20, 00, 00, DateTimeKind.Utc), signatureVerifier: hs256Verifier);
        }

        [Fact]
        public async void ThrowsWhenRS256SignatureIsInvalid()
        {
            var token = "<KEY>";

            var rs256Verifier = new AsymmetricSignatureVerifier(signingKeys.Keys);

            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken(token, signedReqs, new DateTime(2019, 11, 1, 11, 00, 00), rs256Verifier));
            Assert.Equal("Invalid ID token signature.", ex.Message);
        }

        [Fact]
        public async void ThrowsWhenHS256SignatureIsInvalid()
        {
            var token = "<KEY>";

            var hs256Verifier = SymmetricSignatureVerifier.FromClientSecret("fee96dfce7ebfba9f9e489ae07ff2aaa3b06efe1710e34d92762c61182124e5b");

            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken(token, signedReqs, new DateTime(2019, 11, 1, 11, 00, 00, DateTimeKind.Utc), hs256Verifier));

            Assert.Equal("Invalid ID token signature.", ex.Message);
        }

        [Fact]
        public async void ThrowsWhenAlgIsNone()
        {
            var token = "<KEY>

            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken(token));
            Assert.Equal("Signature algorithm of \"none\" is not supported. Expected the ID token to be signed with \"RS256\".", ex.Message);
        }

        [Fact]
        public async void ThrowsWhenAlgIsInvalid()
        {
            var token = "<KEY>";

            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken(token));
            Assert.Equal("Signature algorithm of \"RS384\" is not supported. Expected the ID token to be signed with \"RS256\".", ex.Message);
        }

        [Fact]
        public async void ThrowsWhenHS256OnAsymmetric()
        {
            var token = "<KEY>";

            var rs256Verifier = new AsymmetricSignatureVerifier(signingKeys.Keys);

            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken(token, signatureVerifier: rs256Verifier));
            Assert.Equal("Signature algorithm of \"HS256\" is not supported. Expected the ID token to be signed with \"RS256\".", ex.Message);
        }

        [Fact]
        public async void ThrowsWhenRS256OnSymmetric()
        {
            var token = "<KEY>";

            var hs256Verifier = SymmetricSignatureVerifier.FromClientSecret("fee96dfce7ebfba9f9e489ae07ff2aaa3b06efe1710e34d92762c61182124e5b");

            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken(token, signatureVerifier: hs256Verifier));
            Assert.Equal("Signature algorithm of \"RS256\" is not supported. Expected the ID token to be signed with \"HS256\".", ex.Message);
        }

        [Fact]
        public async void ThrowsWhenIssMissing()
        {
            var token = "<KEY>";

            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken(token));
            Assert.Equal("Issuer (iss) claim must be a string present in the ID token.", ex.Message);
        }

        [Fact]
        public async void ThrowsWhenIssInvalid()
        {
            var token = "<KEY>";

            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken(token));
            Assert.Equal("Issuer (iss) claim mismatch in the ID token; expected \"https://tokens-test.auth0.com/\", found \"something-else\".", ex.Message);
        }

        [Fact]
        public async void ThrowsWhenSubMissing()
        {
            var token = "<KEY>";

            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken(token));
            Assert.Equal("Subject (sub) claim must be a string present in the ID token.", ex.Message);
        }

        [Fact]
        public async void ThrowsWhenAudMissing()
        {
            var token = "<KEY>";

            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken(token));
            Assert.Equal("Audience (aud) claim must be a string or array of strings present in the ID token.", ex.Message);
        }

        [Fact]
        public async void ThrowsWhenAudDoesNotContainAudience()
        {
            var token = "<KEY>";

            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken(token));
            Assert.Equal("Audience (aud) claim mismatch in the ID token; expected \"tokens-test-123\" but was not one of \"external-test-999\".", ex.Message);
        }

        [Fact]
        public async void ThrowsWhenExpMissing()
        {
            var token = "<KEY>";

            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken(token));
            Assert.Equal("Expiration Time (exp) claim must be an integer present in the ID token.", ex.Message);
        }

        [Fact]
        public async void ThrowsWhenExpIndicatesExpired()
        {
            var token = "<KEY>";

            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken(token));
            Assert.Equal("Expiration Time (exp) claim error in the ID token; current time (1568023200) is after expiration time (1568008094).", ex.Message);
        }

        [Fact]
        public async void ThrowsWhenIatMissing()
        {
            var token = "<KEY>";

            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken(token));
            Assert.Equal("Issued At (iat) claim must be an integer present in the ID token.", ex.Message);
        }

        [Fact]
        public async void ThrowsWhenIatIndicatesNotYetValid()
        {
            var token = "<KEY>";

            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken(token));
            Assert.Equal("Issued At (iat) claim error in the ID token; current time (1568023200) is before issued at time (1568180894).", ex.Message);
        }

        [Fact]
        public async void ThrowsWhenNonceIsMissing()
        {
            var token = "<KEY>";

            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken(token));
            Assert.Equal("Nonce (nonce) claim must be a string present in the ID token.", ex.Message);
        }

        [Fact]
        public async void ThrowsWhenNonceIsNotNonce()
        {
            var token = "<KEY>--5caRRydThT01nVxnGatxNcbVxO0duahWIIJlEHjMVeIyA_Ct1iFfm-JV_j8Wo1w9bvh4ReJ3h6N9NBN9_B8Js4WPjNO_O947dNafwmWoVuTPTEIuf26_7UOvdrW0bjeMa5tRE_5topKVnUz7wRPJNIWiyNUSUSXGHxgE4ABa-TYoVOTQlgBjQo3Q";

            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken(token));
            Assert.Equal("Nonce (nonce) claim mismatch in the ID token; expected \"a1b2c3d4e5\", found \"000999\".", ex.Message);
        }

        [Fact]
        public async void SucceedsWhenNonceShouldBeIgnored()
        {
            var token = "<KEY>";

            var reqs = new IdTokenRequirements("https://tokens-test.auth0.com/", "tokens-test-123", TimeSpan.FromMinutes(5))
            {
                MaxAge = TimeSpan.FromSeconds(100)
            };

            await ValidateToken(token, reqs);
        }

        [Fact]
        public async void ThrowsWhenMultiAudAndNoAzp()
        {
            var token = "<KEY>";

            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken(token));
            Assert.Equal("Authorized Party (azp) claim must be a string present in the ID token when Audiences (aud) claim has multiple values.", ex.Message);
        }

        [Fact]
        public async void ThrowsWhenMultiAudAndAzpDoesNotMatchAudience()
        {
            var token = "<KEY>";

            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken(token));
            Assert.Equal("Authorized Party (azp) claim mismatch in the ID token; expected \"tokens-test-123\", found \"external-test-999\".", ex.Message);
        }

        [Fact]
        public async void ThrowsWhenMaxAgeRequestedButAuthTimeMissing()
        {
            var token = "<KEY>";

            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken(token));
            Assert.Equal("Authentication Time (auth_time) claim must be an integer present in the ID token when MaxAge specified.", ex.Message);
        }

        [Fact]
        public async void ThrowsWhenMaxAgeRequestButAuthTimeExpired()
        {
            var token = "<KEY>";

            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken(token));
            Assert.Equal("Authentication Time (auth_time) claim in the ID token indicates that too much time has passed since the last end-user authentication. Current time (1568023200) is after last auth at 1568008254.", ex.Message);
        }
    }
}
<commit_msg>Ensure unit test dates are utc to avoid time zone issues on CI<commit_after>﻿using Auth0.AuthenticationApi.IntegrationTests.Tokens;
using Auth0.AuthenticationApi.Tokens;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Threading.Tasks;
using Xunit;

namespace Auth0.OidcClient.Core.UnitTests.Tokens
{
    public class IdTokenValidatorUnitTests
    {
        private static readonly DateTime tokensWereValid = new DateTime(2019, 9, 9, 10, 00, 00, DateTimeKind.Utc);
        private static readonly ISignatureVerifier rs256NoSignature = new NoSignatureVerifier(new[] { "RS256" });

        private static readonly IdTokenRequirements defaultReqs =
            new IdTokenRequirements("https://tokens-test.auth0.com/", "tokens-test-123", TimeSpan.FromMinutes(1))
            {
                Nonce = "a1b2c3d4e5",
                MaxAge = TimeSpan.FromSeconds(100)
            };

        private static readonly JsonWebKeySet signingKeys = new JsonWebKeySet("{\"keys\":[{\"alg\":\"RS256\",\"kty\":\"RSA\",\"use\":\"sig\",\"x5c\":[\"<KEY>\"],\"n\":\"<KEY>\",\"e\":\"AQAB\",\"kid\":\"<KEY>\",\"x5t\":\"<KEY>RGQQ\"}]}");

        private static readonly IdTokenRequirements signedReqs =
            new IdTokenRequirements("https://auth0-dotnet-integration-tests.auth0.com/", "qmss9A66stPWTOXjR6X1OeA0DLadoNP2", TimeSpan.FromMinutes(1))
            {
                Nonce = "SOrHOau9q0itx4iTF_iX2w"
            };

        private Task ValidateToken(string token, IdTokenRequirements reqs = null, DateTime? when = null, ISignatureVerifier signatureVerifier = null)
        {
            return IdTokenValidator.AssertTokenMeetsRequirements(reqs ?? defaultReqs, token, when ?? tokensWereValid, signatureVerifier ?? rs256NoSignature);
        }

        [Fact]
        public async void ThrowsWhenIdTokenIsNull()
        {
            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken(null));
            Assert.Equal("ID token is required but missing.", ex.Message);
        }

        [Fact]
        public async void ThrowsWhenIdTokenIsEmpty()
        {
            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken(""));
            Assert.Equal("ID token is required but missing.", ex.Message);
        }

        [Fact]
        public async void ThrowsWhenIdTokenIsWhitespace()
        {
            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken("  "));
            Assert.Equal("ID token is required but missing.", ex.Message);
        }

        [Fact]
        public async void ThrowsWhenIdTokenCanNotBeDecoded()
        {
            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken("@#$?Not A Valid Token@#$!"));
            Assert.Equal("ID token could not be decoded.", ex.Message);
        }

        [Fact]
        public async void SucceedsWhenRS256SignatureIsValid()
        {
            var token = "<KEY>";

            var rs256Verifier = new AsymmetricSignatureVerifier(signingKeys.Keys);

            await ValidateToken(token, signedReqs, when: new DateTime(2019, 11, 2, 0, 0, 00, DateTimeKind.Utc), signatureVerifier: rs256Verifier);
        }

        [Fact]
        public async void SucceedsWhenHS256SignatureIsValid()
        {
            var token = "<KEY>";

            var hs256Verifier = SymmetricSignatureVerifier.FromClientSecret("<KEY>");

            await ValidateToken(token, signedReqs, when: new DateTime(2019, 11, 2, 0, 0, 00, DateTimeKind.Utc), signatureVerifier: hs256Verifier);
        }

        [Fact]
        public async void ThrowsWhenRS256SignatureIsInvalid()
        {
            var token = "<KEY>";

            var rs256Verifier = new AsymmetricSignatureVerifier(signingKeys.Keys);

            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken(token, signedReqs, signatureVerifier: rs256Verifier));
            Assert.Equal("Invalid ID token signature.", ex.Message);
        }

        [Fact]
        public async void ThrowsWhenHS256SignatureIsInvalid()
        {
            var token = "<KEY>";

            var hs256Verifier = SymmetricSignatureVerifier.FromClientSecret("fee96dfce7ebfba9f9e489ae07ff2aaa3b06efe1710e34d92762c61182124e5b");

            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken(token, signedReqs, signatureVerifier: hs256Verifier));

            Assert.Equal("Invalid ID token signature.", ex.Message);
        }

        [Fact]
        public async void ThrowsWhenAlgIsNone()
        {
            var token = "<KEY>TY4MDk0NDk0LjIyNH0.";

            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken(token));
            Assert.Equal("Signature algorithm of \"none\" is not supported. Expected the ID token to be signed with \"RS256\".", ex.Message);
        }

        [Fact]
        public async void ThrowsWhenAlgIsInvalid()
        {
            var token = "<KEY>";

            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken(token));
            Assert.Equal("Signature algorithm of \"RS384\" is not supported. Expected the ID token to be signed with \"RS256\".", ex.Message);
        }

        [Fact]
        public async void ThrowsWhenHS256OnAsymmetric()
        {
            var token = "<KEY>";

            var rs256Verifier = new AsymmetricSignatureVerifier(signingKeys.Keys);

            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken(token, signatureVerifier: rs256Verifier));
            Assert.Equal("Signature algorithm of \"HS256\" is not supported. Expected the ID token to be signed with \"RS256\".", ex.Message);
        }

        [Fact]
        public async void ThrowsWhenRS256OnSymmetric()
        {
            var token = "<KEY>";

            var hs256Verifier = SymmetricSignatureVerifier.FromClientSecret("fee96dfce7ebfba9f9e489ae07ff2aaa3b06efe1710e34d92762c61182124e5b");

            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken(token, signatureVerifier: hs256Verifier));
            Assert.Equal("Signature algorithm of \"RS256\" is not supported. Expected the ID token to be signed with \"HS256\".", ex.Message);
        }

        [Fact]
        public async void ThrowsWhenIssMissing()
        {
            var token = "<KEY>";

            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken(token));
            Assert.Equal("Issuer (iss) claim must be a string present in the ID token.", ex.Message);
        }

        [Fact]
        public async void ThrowsWhenIssInvalid()
        {
            var token = "<KEY>";

            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken(token));
            Assert.Equal("Issuer (iss) claim mismatch in the ID token; expected \"https://tokens-test.auth0.com/\", found \"something-else\".", ex.Message);
        }

        [Fact]
        public async void ThrowsWhenSubMissing()
        {
            var token = "<KEY>";

            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken(token));
            Assert.Equal("Subject (sub) claim must be a string present in the ID token.", ex.Message);
        }

        [Fact]
        public async void ThrowsWhenAudMissing()
        {
            var token = "<KEY>";

            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken(token));
            Assert.Equal("Audience (aud) claim must be a string or array of strings present in the ID token.", ex.Message);
        }

        [Fact]
        public async void ThrowsWhenAudDoesNotContainAudience()
        {
            var token = "<KEY>";

            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken(token));
            Assert.Equal("Audience (aud) claim mismatch in the ID token; expected \"tokens-test-123\" but was not one of \"external-test-999\".", ex.Message);
        }

        [Fact]
        public async void ThrowsWhenExpMissing()
        {
            var token = "<KEY>";

            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken(token));
            Assert.Equal("Expiration Time (exp) claim must be an integer present in the ID token.", ex.Message);
        }

        [Fact]
        public async void ThrowsWhenExpIndicatesExpired()
        {
            var token = "<KEY>";

            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken(token));
            Assert.Equal("Expiration Time (exp) claim error in the ID token; current time (1568023200) is after expiration time (1568008094).", ex.Message);
        }

        [Fact]
        public async void ThrowsWhenIatMissing()
        {
            var token = "<KEY>";

            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken(token));
            Assert.Equal("Issued At (iat) claim must be an integer present in the ID token.", ex.Message);
        }

        [Fact]
        public async void ThrowsWhenIatIndicatesNotYetValid()
        {
            var token = "<KEY>";

            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken(token));
            Assert.Equal("Issued At (iat) claim error in the ID token; current time (1568023200) is before issued at time (1568180894).", ex.Message);
        }

        [Fact]
        public async void ThrowsWhenNonceIsMissing()
        {
            var token = "<KEY>";

            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken(token));
            Assert.Equal("Nonce (nonce) claim must be a string present in the ID token.", ex.Message);
        }

        [Fact]
        public async void ThrowsWhenNonceIsNotNonce()
        {
            var token = "<KEY>";

            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken(token));
            Assert.Equal("Nonce (nonce) claim mismatch in the ID token; expected \"a1b2c3d4e5\", found \"000999\".", ex.Message);
        }

        [Fact]
        public async void SucceedsWhenNonceShouldBeIgnored()
        {
            var token = "<KEY>";

            var reqs = new IdTokenRequirements("https://tokens-test.auth0.com/", "tokens-test-123", TimeSpan.FromMinutes(5))
            {
                MaxAge = TimeSpan.FromSeconds(100)
            };

            await ValidateToken(token, reqs);
        }

        [Fact]
        public async void ThrowsWhenMultiAudAndNoAzp()
        {
            var token = "<KEY>";

            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken(token));
            Assert.Equal("Authorized Party (azp) claim must be a string present in the ID token when Audiences (aud) claim has multiple values.", ex.Message);
        }

        [Fact]
        public async void ThrowsWhenMultiAudAndAzpDoesNotMatchAudience()
        {
            var token = "<KEY>";

            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken(token));
            Assert.Equal("Authorized Party (azp) claim mismatch in the ID token; expected \"tokens-test-123\", found \"external-test-999\".", ex.Message);
        }

        [Fact]
        public async void ThrowsWhenMaxAgeRequestedButAuthTimeMissing()
        {
            var token = "<KEY>";

            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken(token));
            Assert.Equal("Authentication Time (auth_time) claim must be an integer present in the ID token when MaxAge specified.", ex.Message);
        }

        [Fact]
        public async void ThrowsWhenMaxAgeRequestButAuthTimeExpired()
        {
            var token = "<KEY>--<KEY>";

            var ex = await Assert.ThrowsAsync<IdTokenValidationException>(() => ValidateToken(token));
            Assert.Equal("Authentication Time (auth_time) claim in the ID token indicates that too much time has passed since the last end-user authentication. Current time (1568023200) is after last auth at 1568008254.", ex.Message);
        }
    }
}

{'fraction_non_alphanumeric': 0.11147181755468084, 'fraction_numerical': 0.027878099257395608, 'mean_word_length': 2.529142202491766, 'pattern_counts': {'":': 18, '<': 112, '<?xml version=': 0, '>': 162, 'https://': 8, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7490587', 'n_tokens_mistral': 7205, 'n_tokens_neox': 6671, 'n_words': 1728}