0

I have a Blazor WASM client app that is trying to send a cookie to my asp.net api, both on localhost but on different ports so CORS is required.

I've configured and applied a CORS policy on the API side but I'm having trouble figuring out the correct options or header setting on the client request side. In Chrome dev tools I see the cookie in the header but it doesn't seem to reach the API as the cookie count on that side returns zero.

I've tested the API controllers directly with GET in the browser and the cookie works so it must be an issue with CORS and cookies together.

This is a snippet of code from an action on the Blazor WASM client side: (I've commented out other failed configuration attempts)

private async void CheckCookie()
{
    HttpClient client = new HttpClient();
    HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, "https://localhost:7139/ValidateCookie");
    //requestMessage.Options.Set(new HttpRequestOptionsKey<string>(),"true");
    //requestMessage.Options.Append(new KeyValuePair<string, object>("credentials","include"));
    requestMessage.Options.Set(new HttpRequestOptionsKey<string>("Access-Control-Request-Headers"),"Cookie");
    requestMessage.Options.Set(new HttpRequestOptionsKey<string>("Access-Control-Allow-Origin"),"http://localhost:5196");
    requestMessage.Options.Set(new HttpRequestOptionsKey<string>("Access-Control-Allow-Methods"),"GET");
    //requestMessage.Headers.Add("Access-Control-Allow-Credentials","true");
    //requestMessage.Headers.Add("withCredentials","true");
    CommunityObject[] subbedCommunities;
    List<CommunityObject> listSubbedCommunities = new List<CommunityObject>();
    HttpResponseMessage returnMessage = await client.SendAsync(requestMessage);
    var stream = returnMessage.Content.ReadAsStreamAsync();
    var contentstring = returnMessage.Content.ReadAsStringAsync();
    Console.WriteLine("Community CheckCookie return stream result: " + stream.Result);
    cookieresult = contentstring.Result;

}

Here is my current program.cs CORS configuration: (I've also tried with just setting the origins as the localhost:port-the-client-is-using)

builder.Services.AddCors(options =>
    {
    options.AddPolicy("CookiePolicy",
    policy =>
    {
        policy.AllowCredentials().AllowAnyHeader().AllowAnyMethod().SetIsOriginAllowed(origin => new Uri(origin).Host == "localhost");
    });

Here is the controller being called:

public class ValidateCookieToken : ControllerBase
{

    [EnableCors("CookiePolicy")]
    [HttpGet("/ValidateCookie")]
    public String Get()
    {
        String bearertoken;
        Console.WriteLine("ValidateCookies Headers Keys: " + Request.Headers.Keys);
        foreach (var VARIABLE in Request.Headers.Keys)
        {
            Console.WriteLine("ValCookie Key: " + VARIABLE + " - Value: " + Request.Headers[VARIABLE]);
        }
        Console.WriteLine("ValidateCookies current cookie count: " + Request.Cookies.Count);
        Console.WriteLine("Validatecookies cookie keys: " + Request.Cookies.Keys);
        Console.WriteLine("ValCook headers cookie: " + Request.Headers.Cookie.ToString());
        Request.Cookies.TryGetValue("bearer", out bearertoken);
        String decodedbearer = Encoding.ASCII.GetString(Convert.FromBase64String(bearertoken));
        return decodedbearer;
    }
}

On top of all of this, is there a way to log CORS transactions so I can atleast debug it from that end. As it stands I have no idea which side, client or API, the CORS cookie is getting blocked at.

Edit: Below is the login controller which adds the cookie.

[HttpGet("/Login")]
    public String Get(String Email, String Pass)
    {
        String token = null;
        token = Auth.Login(Email, Pass);
        if (token != null)
        {
            String basicauth = Convert.ToBase64String(Encoding.ASCII.GetBytes(Email+":"+token));
            CookieOptions cookieOptions = new CookieOptions();
            Console.WriteLine("Cookie path is: " + cookieOptions.Path);
            Console.WriteLine("Cookie domain is: " + cookieOptions.Domain);
            Console.WriteLine("Cookie isEssential: " + cookieOptions.IsEssential);
            Console.WriteLine("Cookie Samesite: " + cookieOptions.SameSite);
            Console.WriteLine("Cookie secure: " + cookieOptions.Secure);
            Console.WriteLine("Cookie expires: " + cookieOptions.Expires);
            Console.WriteLine("Cookie httponly: " + cookieOptions.HttpOnly);
            Console.WriteLine("Cookie max age: " + cookieOptions.MaxAge);
            cookieOptions.IsEssential = true;
            cookieOptions.SameSite = SameSiteMode.Lax;
            cookieOptions.Secure = false;
            Response.Cookies.Append("bearer",basicauth,cookieOptions);
            Console.WriteLine("Cookie count after login: " + Request.Cookies.Count);
            return basicauth;
        }
        return "token was null";
    }
midramble
  • 13
  • 3
  • Yes, the requests arrive as I can read other headers from those requests but the problem is that the cookie isn't being sent with the requests, or is being blocked on the API side as being received because the cookie doesn't show up in the header on the API side and request.cookies is empty. I assume its either the client isn't sending it (as by default it doesn't for CORS) or I've misconfigured CORS on the API side to allow credentials. I'll edit the post to show the other controller which adds the cookie. – midramble Jul 07 '22 at 14:35
  • Also, when in the dev tools in chrome I can see the cookie in the header so I had assumed it was at least sending, but I don't know how to verify that the browser is actually sending it. – midramble Jul 07 '22 at 14:35
  • Try fiddler http inspector – fuzzybear Jul 07 '22 at 17:12
  • Thanks, tried fiddler and it seems to confirm that the cookie isn't getting sent from the browser so my code is breaking there. Specifically it doesn't send the cookie when the request tunnel goes to the API port meaning its a CORS/cookie combination issue. I've found resources online that mention a JS fix but not seeing a Blazor solution. Was hoping to find a request option or header I can add that would signal the browser to send, but no luck. – midramble Jul 07 '22 at 20:52

1 Answers1

0

Do you get any message on the client side? It could be a preflight thing where your API doesn't allow cookie headers, or Access-Control-Allow-Credentials needs to be configured

Set cookies for cross origin requests

https://livebook.manning.com/book/cors-in-action/chapter-5/4

Shuryno
  • 532
  • 3
  • 13
  • According to fiddler, that does appear to be the issue; however, in Blazor, the only fixes I'm finding (as I've already tried setting allow credential headers) is to use a JSInterop or setting request.BrowserRequestCredentials to include. I would prefer the latter; however, it requires the Microsoft.AspNetCore.Components.WebAssembly.Http package, which for some reason isn't compatible with aspnet core 6.0 with target 6.0. After installing it gives an error saying it's only compatible with .net framework 6.0 which I'm honestly not sure how to install. I have trouble with .net package versioning – midramble Jul 12 '22 at 04:46