Repository: dotnet/aspnetcore
File: src/Security/Authentication/test/JwtBearerTests_Handler.cs (C#)

Code before:

        var tokenText = new JwtSecurityTokenHandler().WriteToken(token);

        using var host = await CreateHost(o =>
        {
            o.SaveToken = true;
            o.TokenValidationParameters = new TokenValidationParameters()
            {
                ValidIssuer = "issuer.contoso.com",
                ValidAudience = "audience.contoso.com",
                IssuerSigningKey = key,
            };
        });

        var newBearerToken = "Bearer " + tokenText;
        using var server = host.GetTestServer();
        var response = await SendAsync(server, "http://example.com/expiration", newBearerToken);
        Assert.Equal(HttpStatusCode.OK, response.Response.StatusCode);
        var responseBody = await response.Response.Content.ReadAsStringAsync();
        using var dom = JsonDocument.Parse(responseBody);
        Assert.Equal(JsonValueKind.Null, dom.RootElement.GetProperty("issued").ValueKind);

        var expiresElement = dom.RootElement.GetProperty("expires");
        Assert.Equal(JsonValueKind.String, expiresElement.ValueKind);

        var elementValue = DateTime.Parse(expiresElement.GetString(), CultureInfo.InvariantCulture);
        var elementValueUtc = elementValue.ToUniversalTime();
        // roundtrip DateTime.MaxValue through parsing because it is lossy and we
        // need equivalent values to compare against.
        var max = DateTime.Parse(DateTime.MaxValue.ToString(CultureInfo.InvariantCulture), CultureInfo.InvariantCulture);

        Assert.Equal(max, elementValueUtc);
    }

    [Fact]
    public void CanReadJwtBearerOptionsFromConfig()
    {
        var services = new ServiceCollection();
        var key = "qPG6tDtfxFYZifHW3sEueQ==";
        var config = new ConfigurationBuilder().AddInMemoryCollection([
            new("Authentication:Schemes:Bearer:ValidIssuer", "dotnet-user-jwts"),
            new("Authentication:Schemes:Bearer:ValidIssuers:0", "dotnet-user-jwts-2"),
            new("Authentication:Schemes:Bearer:ValidAudience", "http://localhost:5000"),
            new("Authentication:Schemes:Bearer:ValidAudiences:0", "http://localhost:5001"),
            new("Authentication:Schemes:Bearer:BackchannelTimeout", "00:01:00"),
            new("Authentication:Schemes:Bearer:RequireHttpsMetadata", "false"),
            new("Authentication:Schemes:Bearer:SaveToken", "True"),
            new("Authentication:Schemes:Bearer:SigningKeys:0:Issuer", "dotnet-user-jwts"),
            new("Authentication:Schemes:Bearer:SigningKeys:0:Value", key),
            new("Authentication:Schemes:Bearer:SigningKeys:0:Length", "32"),
        ]).Build();

Review comment (suggestion):
Consider using DateTime.ParseExact or DateTimeOffset.Parse for more robust parsing of JWT timestamps, as JWT standards typically use ISO 8601 format. This would be more explicit about the expected format and reduce ambiguity.
```suggestion
        var elementValueUtc = DateTime.ParseExact(expiresElement.GetString(), "yyyy-MM-ddTHH:mm:ss.fffffffK", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal);
```

Code after:

        var tokenText = new JwtSecurityTokenHandler().WriteToken(token);

        using var host = await CreateHost(o =>
        {
            o.SaveToken = true;
            o.TokenValidationParameters = new TokenValidationParameters()
            {
                ValidIssuer = "issuer.contoso.com",
                ValidAudience = "audience.contoso.com",
                IssuerSigningKey = key,
            };
        });

        var newBearerToken = "Bearer " + tokenText;
        using var server = host.GetTestServer();
        var response = await SendAsync(server, "http://example.com/expiration", newBearerToken);
        Assert.Equal(HttpStatusCode.OK, response.Response.StatusCode);
        var responseBody = await response.Response.Content.ReadAsStringAsync();
        using var dom = JsonDocument.Parse(responseBody);
        Assert.Equal(JsonValueKind.Null, dom.RootElement.GetProperty("issued").ValueKind);

        var expiresElement = dom.RootElement.GetProperty("expires");
        Assert.Equal(JsonValueKind.String, expiresElement.ValueKind);

        var elementValueUtc = DateTime.Parse(expiresElement.GetString(), CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal);
        // roundtrip DateTime.MaxValue through parsing because it is lossy and we
        // need equivalent values to compare against.
        var max = DateTime.Parse(DateTime.MaxValue.ToString(CultureInfo.InvariantCulture), CultureInfo.InvariantCulture);

        Assert.Equal(max, elementValueUtc);
    }

    [Fact]
    public void CanReadJwtBearerOptionsFromConfig()
    {
        var services = new ServiceCollection();
        var key = "qPG6tDtfxFYZifHW3sEueQ==";
        var config = new ConfigurationBuilder().AddInMemoryCollection([
            new("Authentication:Schemes:Bearer:ValidIssuer", "dotnet-user-jwts"),
            new("Authentication:Schemes:Bearer:ValidIssuers:0", "dotnet-user-jwts-2"),
            new("Authentication:Schemes:Bearer:ValidAudience", "http://localhost:5000"),
            new("Authentication:Schemes:Bearer:ValidAudiences:0", "http://localhost:5001"),
            new("Authentication:Schemes:Bearer:BackchannelTimeout", "00:01:00"),
            new("Authentication:Schemes:Bearer:RequireHttpsMetadata", "false"),
            new("Authentication:Schemes:Bearer:SaveToken", "True"),
            new("Authentication:Schemes:Bearer:SigningKeys:0:Issuer", "dotnet-user-jwts"),
            new("Authentication:Schemes:Bearer:SigningKeys:0:Value", key),
            new("Authentication:Schemes:Bearer:SigningKeys:0:Length", "32"),
        ]).Build();
        services.AddSingleton<IConfiguration>(config);