Unittest with RestSharp

We’re developing an aspnet core website with webapi backend all on a cloud platform. The auth part is implemented with openidconnect and cookies. Every tab is a new application to reduce release and test times. For the website / applications we have a razor class library that contains the main layout. See all posts in this series cloudnative

Our adapters use IRestClient that is injected during construction. Only using the interface is hard, since it is very limited. Ease of use is with the extension methods, but needs some extra setup. The magic is in the SetupRestClient helper method that configures the use of json and returns the response (with data) constructed with the GetContent* helper methods. Below an example for testing the get of 6 records.

using RestSharp;    // see https://restsharp.dev
using AutoMoqCore;  // see https://github.com/thomashfr/AutoMoqCore

private static void SetupRestclient(AutoMoqer autoMoqer, RestResponse response)
{
  var defaultSerializer = new SerializerConfig();
  defaultSerializer.UseDefaultSerializers();
  var serializers = new RestSerializers(defaultSerializer);
  var fakeClient = autoMoqer.GetMock<IRestClient>();
  fakeClient.SetupGet(x => x.Serializers).Returns(serializers);
  fakeClient.Setup(x => x.ExecuteAsync(
    It.IsAny<RestRequest>(),
    It.IsAny<CancellationToken>()))
  .ReturnsAsync(response);
}

private static string GetContentFor6Records()
{
  var items = Enumerable.Repeat(new Record(), 6);
  return JsonSerializer.Serialize(items);
}

[TestMethod]
public async Task GetRecords_returns_6_items()
{
  var autoMoqer = new AutoMoqer();
  // arrange
  SetupRestclient(autoMoqer, new RestResponse { Content = GetContentFor6Records() });
  //act
  var testObject = autoMoqer.Create<RecordApiAdapter>();
  // assert
  var items = await testObject.GetRecords();
  Assert.AreEqual(6, items.Length);
}
Posted in Development | Tagged , | Leave a comment

Call upstream api with token from jQuery

We’re developing an aspnet core website with webapi backend all on a cloud platform. The auth part is implemented with openidconnect and cookies. Every tab is a new application to reduce release and test times. For the website / applications we have a razor class library that contains the main layout. See all posts in this series cloudnative

In Call upstream api with token we described how to get the token in the controller – the backend. Now we need to call the api from jQuery – the frontend. For this we implemented methods on the controller that can be called from jQuery. Because the request is for the samen site, the cookie is send with the request and the controller can access the token for us and do the upstream api request.

// controller = backend
public class RecordController : Controller {
  // other methods for aspnet core mvc like Index
 
  // called from frontend with jQuery
  [Authorize]
  public async Task<IActionResult> CallupstreamApi(
        [Required(AllowEmptyStrings = false)] string recordid)
  {
    if (!ModelState.IsValid) return BadRequest(ModelState);
    // call upstream api with IRestClient and recordid
    var request = new RestRequest("record/{id}");
    request.AddUrlSegment("id", recordid);
    var response = await _restClient.ExecuteAsync<record>(request, default);
    // return json for easy parsing in jQuery
    return Json(response.data);
  }
}
// index.cshtml = frontend
function RequestRecordFromUpstreamApi () {
  $.ajax({
    type: 'GET',
    url: '@Url.Action("CallupstreamApi")',
    datatype: 'json',
    data: { 
      recordid: 'my_id_for_record_1'
    },
    success: function (record) { console.log(record.id); },
    error: function (xhr, status, error) { console.log(xhr.responseText); }
  });
}
Posted in Development | Tagged , , | Leave a comment

Call upstream api with token

We’re developing an aspnet core website with webapi backend all on a cloud platform. The auth part is implemented with openidconnect and cookies. Every tab is a new application to reduce release and test times. For the website / applications we have a razor class library that contains the main layout. See all posts in this series cloudnative

To call an upstream api from the website we need a token. This was added to the cookie in Fix HTTP431 Request header fields too large. Now we can get the token with GetTokenAsync, configure the client and inject the client into our adapter.

using RestSharp; // see https://restsharp.dev

builder.Services.AddScoped<IRestClient>(options =>
{
    var environment = options.GetRequiredService<IConfiguration>();
    var url = environment.GetValue<string>("url")!;
    var client = new RestClient(url);

    // make sure token is saved
    var context = options.GetRequiredService<IHttpContextAccessor>();
    var token = context.HttpContext!.GetTokenAsync("access_token").Result;
    client.AddDefaultHeader("Authorization", $"Bearer {token}");

    return client;
});
Posted in Development | Tagged | 1 Comment

Fix HTTP431 Request header fields too large

We’re developing an aspnet core website with webapi backend all on a cloud platform. The auth part is implemented with openidconnect and cookies. Every tab is a new application to reduce release and test times. For the website / applications we have a razor class library that contains the main layout. See all posts in this series cloudnative

Today we received feedback that some users experience a HTTP431 exception when browsing the website. This was right after we added the access_token so it had to be that. The message is “request header fields too large” – would this be the feared token bloat where some users would have endless claims making the token too large?

Turns out we’re not alone and the solution for this was already on GitHub: https://github.com/dotnet/aspnetcore/issues/30016. Our solution was to remove SaveTokens = true and add the access_token on the OnTokenResponseReceived event (we’re using codeflow) Solution in code below.

.AddOpenIdConnect(opt =>
  // o.SaveTokens = true; // results in HTTP431 for some users
  opt.Events = new OpenIdConnectEvents() {
    OnTokenResponseReceived = c => {
      c.Properties.StoreTokens(new[] { 
        // store only the access_token
        new AuthenticationToken {
          Name = "access_token",
          Value = c.TokenEndpointResponse.AccessToken
        }
      });
      return Task.CompletedTask;
    }
  };

In the developer tools (F12) on the application tab you can see the cookie for the website. With SaveTokens = true it would be 7 or more chunks. After the change the cookie was only 2 chunks. Problem solved.

Posted in Development | Tagged | 1 Comment

Unable to unprotect the message.State

We’re developing an aspnet core website with webapi backend all on a cloud platform. The auth part is implemented with openidconnect and cookies. Every tab is a new application to reduce release and test times. For the website / applications we have a razor class library that contains the main layout. See all posts in this series cloudnative

Debugging on localhost worked like a charm. But after deploying with 2 instances we received errors. The logging showed: “Unable to unprotect the message.State”. We found that this was documented on https://github.com/AzureAD/microsoft-identity-web/wiki/Deploying-Web-apps-to-App-services-as-Linux-containers#issue-with-scaled-out-web-apps-in-app-services. Since we used 2 instances the encryption key of one instance was unknown to the other instance – the keys needed to be shared.

We configured the applications to use Redis for saving (and sharing) the keys. This also solved the requirement that a user should only login once and have access to all applications.

Posted in Development, Security | Tagged , | Leave a comment