CORS Access-Control-Allow-Credentials not being set

I have been working on gracefully handling token expirations in one of our React app, and so I set the expiry to one minute as follows

new JwtAuthProvider() {
    ExpireTokensIn        = TimeSpan.FromMinutes(1),  // JWT Token Expiry
    ExpireRefreshTokensIn = TimeSpan.FromDays(365), // Refresh Token Expiry
    UseTokenCookie = false, AllowInQueryString = true, AuthKeyBase64 = 
        Environment.GetEnvironmentVariable("JWT_KEY")},
}

and cors as follows:

Plugins.Add(new CorsFeature(
    allowOriginWhitelist: new[] { "http://localhost:3000"},
    allowCredentials: true,
    allowedHeaders: "Content-Type, Allow, Authorization, X-Args"));

I clear session cookie storage, the app gets a 401 on the first api call, properly redirects to login, and renders the first page including several api calls.

Wait one minute, and start getting CORS errors as follows:
Browser error:
Access to fetch at ‘https://localhost:5001/json/reply/GetBidsReq’ from origin ‘http://localhost:3000’ has been blocked by CORS policy: The value of the ‘Access-Control-Allow-Credentials’ header in the response is ‘’ which must be ‘true’ when the request’s credentials mode is ‘include’.

Request Headers:

GET /json/reply/GetBidsReq HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8
Connection: keep-alive
Host: localhost:5001
Origin: http://localhost:3000
Referer: http://localhost:3000/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36
authorization: Bearer eyJ0eXAiOiJxxxsRQl8LwD6ut9R663JrJwXRJHW0g8U
content-type: application/json
sec-ch-ua: "Chromium";v="110", "Not A(Brand";v="24", "Google Chrome";v="110"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "macOS"

Response Headers:

HTTP/1.1 200 OK
Content-Length: 40
Date: Tue, 07 Mar 2023 02:00:17 GMT
Server: Kestrel
Access-Control-Allow-Origin: http://localhost:3000

Doesn’t look like the CORS GlobalResponseHeaders is being written to the response, unless this HTTP Response doesn’t match the HTTP Request. Can you provide a screenshot from WebInspector’s Header tab showing the full HTTP Request + Response Headers together please.

Where’s the trust?? :).

and console: super weird to get an error on 200

Looks like something’s preventing the GlobalResponseHeaders from being written.

Is your GetBidsReq a normal API? Does it happen with all APIs? (there should be more CORS HTTP Headers returned in the HTTP Response) Will likely need a repro to be able to identify what’s preventing Headers from being written.

Ah shoot I didn’t see the service exception happening - as. follows ( having trouble pasting from debug log completely here…)

   at ServiceStack.ServiceStackHost.ApplyRequestFiltersSingleAsync(IRequest req, IResponse res, Object requestDto) in /home/runner/work/ServiceStack/ServiceStack/ServiceStack/src/ServiceStack/ServiceStackHost.Runtime.cs:line 180
   at ServiceStack.ServiceStackHost.ApplyRequestFiltersAsync(IRequest req, IResponse res, Object requestDto) in /home/runner/work/ServiceStack/ServiceStack/ServiceStack/src/ServiceStack/ServiceStackHost.Runtime.cs:line 144
   at ServiceStack.Host.Handlers.GenericHandler.ProcessRequestAsync(IRequest httpReq, IResponse httpRes, String operationName) in /home/runner/work/ServiceStack/ServiceStack/ServiceStack/src/ServiceStack/Host/Handlers/GenericHandler.cs:line 56:
   at ServiceStack.Auth.JwtAuthProviderReader.AssertJwtPayloadIsValid(JsonObject jwtPayload) in /home/runner/work/ServiceStack/ServiceStack/ServiceStack/src/ServiceStack/Auth/JwtAuthProviderReader.cs:line 879
   at ServiceStack.Auth.JwtAuthProviderReader.CreateSessionFromPayload(IRequest req, JsonObject jwtPayload) in /home/runner/work/ServiceStack/ServiceStack/ServiceStack/src/ServiceStack/Auth/JwtAuthProviderReader.cs:line 850
   at ServiceStack.Auth.JwtAuthProviderReader.AuthenticateBearerToken(IRequest req, IResponse res, String bearerToken) in /home/runner/work/ServiceStack/ServiceStack/ServiceStack/src/ServiceStack/Auth/JwtAuthProviderReader.cs:line 566
   at ServiceStack.Auth.JwtAuthProviderReader.PreAuthenticateAsync(IRequest req, IResponse res) in /home/runner/work/ServiceStack/ServiceStack/ServiceStack/src/ServiceStack/Auth/JwtAuthProviderReader.cs:line 517
   at ServiceStack.AuthenticateAttribute.PreAuthenticateAsync(IRequest req, IEnumerable`1 authProviders) in /home/runner/work/ServiceStack/ServiceStack/ServiceStack/src/ServiceStack/AuthenticateAttribute.cs:line 206
   at ServiceStack.AuthenticateAttribute.ExecuteAsync(IRequest req, IResponse res, Object requestDto) in /home/runner/work/ServiceStack/ServiceStack/ServiceStack/src/ServiceStack/AuthenticateAttribute.cs:line 75
   at ServiceStack.ServiceStackHost.ApplyRequestFiltersSingleAsync(IRequest req, IResponse res, Object requestDto) in /home/runner/work/ServiceStack/ServiceStack/ServiceStack/src/ServiceStack/ServiceStackHost.Runtime.cs:line 180
   at ServiceStack.ServiceStackHost.ApplyRequestFiltersAsync(IRequest req, IResponse res, Object requestDto) in /home/runner/work/ServiceStack/ServiceStack/ServiceStack/src/ServiceStack/ServiceStackHost.Runtime.cs:line 144
   at ServiceStack.Host.Handlers.GenericHandler.ProcessRequestAsync(IRequest httpReq, IResponse httpRes, String operationName) in /home/runner/work/ServiceStack/ServiceStack/ServiceStack/src/ServiceStack/Host/Handlers/GenericHandler.cs:line 56
info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
      Request finished HTTP/1.1 GET https://localhost:5001/json/reply/GetBidsReq application/json - - 200 40 - 4.7969ms
Microsoft.AspNetCore.Hosting.Diagnostics: Information: Request finished HTTP/1.1 GET https://localhost:5001/json/reply/GetBidsReq application/json - - 200 40 - 4.7969ms

That Exception is because the Token is Invalid:

Then why is that a 200…(without the cors headers…) and yes, GetBidsReq is a pretty normal DTO and service implementation.

Where are you getting the Exception from?

The console debug log of dotnet.

Also note, I have this:

 this.ServiceExceptionHandlers.Add((httpReq, request, exception) => {
    //log your exceptions here
    Common.Log.Error("Exception in service " + httpReq.AbsoluteUri,exception);

    return null; //continue with default Error Handling

    //or return your own custom response
    //return DtoUtils.CreateErrorResponse(request, exception);
});

ohhhhh maybe it is this:

  this.UncaughtExceptionHandlers.Add((req, res, operationName, ex) => {
            Common.Log.Error("Exception in service " + req.AbsoluteUri,ex);


     res.Write($"Error: {ex.GetType().Name}: {ex.Message}");
     res.EndRequest(skipHeaders: true);
});

Removing the UncaughtExceptionHandlers seems to have fixed it (modifying skipHeaders did not…). The client is behaving much better now and is handling the expiration transparently which is nice. Thanks for your quick response and help digging in.

1 Like

Yeah this is why we need repro’s, it’s impossible to reproduce without full information.

I understand, but the effort in creating a repro with a big app without giving away source code is pretty high.

The process of creating a repro with empty Services would’ve discovered this issue. Without having full information of what’s causing it means we’re blindly wasting time shooting in the dark.