Home > Software engineering >  How to use custom Jwt settings when validating Jwt's in a test context?
How to use custom Jwt settings when validating Jwt's in a test context?

Time:01-23

I have an ASP.NET Core application which uses the following piece of logic to configure Authentication / Authorization.

services.AddAuthorization(
    static options => options.AddPolicy(
        "Bearer", new AuthorizationPolicyBuilder()
                  .AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)
                  .RequireAuthenticatedUser()
                  .Build()));

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(options => {
            options.Authority = identityProviderEndpoint;

            options.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidateLifetime = true,
                ValidateIssuerSigningKey = true,
                ValidIssuer = identityProviderEndpoint,
                ValidAudience = applicationAudience,
                RequireSignedTokens = true,
            };
        });

Now, this works, when example, validating a token from Auth0. For testing purposes, I want to use custom options (disabling all checks, since it's not important when testing).

Here's a test case I have created with custom options.

[Fact(DisplayName = "HTTP Forbidden: Requesting (Valid JWT) an authorized endpoint (JWT Validation disabled).")]
internal async void RequestingAnEndpointThatRequiresAuthorizationWithAValidJWT()
{
    // ARRANGE.
    HttpClient httpClient = this.webApplicationFactory.WithWebHostBuilder(
                                    builder =>
                                    {
                                        builder.ConfigureTestServices(
                                            services =>
                                            {
                                                var options = new JwtBearerOptions();

                                                options.TokenValidationParameters = new TokenValidationParameters
                                                {

#pragma warning disable CA5404 // "Do not disable token validation checks" - By design. ValidateIssuer = false, ValidateAudience = false, ValidateLifetime = false, #pragma warning restore CA5404 ValidateIssuerSigningKey = false, RequireSignedTokens = false, IssuerSigningKey = new SymmetricSecurityKey( Encoding.UTF8.GetBytes("UTrust.S1gn1ngK3Y!")), };

                                                services.AddSingleton(options);
                                            });
                                    })
                                .CreateClient();

    httpClient.DefaultRequestHeaders.Add(
        "Authorization",
        "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.T7sFpO0XoaJ9JWsu2J1ormK99zs4zIr2s25jjl8RVSw");

    // ACT.
    HttpResponseMessage result = await httpClient.GetAsync("/authorized")
                                                 .ConfigureAwait(false);

    // ASSERT.
    result.Should()
          .HaveStatusCode(HttpStatusCode.OK);
}

I'm passing a JWT which can be validated on https://jwt.io/. The test fails however with an Unauthorized HTTP Status code.

If inside the application, I change the options with the options I'm using in the test, the same token is considered value and I get an HTTP Ok status code.

This is validated using the following cURL request.

curl http://localhost:5160/authorized -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.T7sFpO0XoaJ9JWsu2J1ormK99zs4zIr2s25jjl8RVSw" -v

What am I missing here? Why is the token considered invalid in the test context, but valid in the actual application (if I use the same options in both)?

CodePudding user response:

You registering JwtBearerOptions directly in IoC container, so it doesn't picked up by configuration system.

You need to change code to something like this:

services.Configure(JwtBearerDefaults.AuthenticationScheme, options => {
// ...
});
  • Related