.NET 6: Correlation Cookies Lost Behind Reverse Proxy After Authentication

I’m experiencing an issue with my .NET 6 application where correlation cookies are lost after authentication when deployed behind a reverse proxy. The reverse proxy handles HTTPS, so the application itself doesn’t manage HTTPS directly.

The application works correctly when running locally, but in the production environment (behind the reverse proxy), the correlation cookies seem to be lost after authentication.


var builder = WebApplication.CreateBuilder(args);
builder.Logging.AddConsole();
var config = new ConfigurationBuilder()
    .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
    .Build();

builder.Services.AddCors(options =>
{
    options.AddPolicy("AllowAll",
               builder =>
               {
                   builder.AllowAnyOrigin()
                          .AllowAnyMethod()
                          .AllowAnyHeader();
               });
});

string SecurityLevelClaimPolicy = "SecurityLevelClaimPolicy";
string SecurityLevelClaim = "Claims";
Settings _settings = new Settings();
_settings.IdConfiguration = new IdConfiguration();
//_settings.ClientType = ClientType.ApiAccess;


_settings.ClientType = ClientType.ApiAccessForMultiTenantClient;
_settings.ApiAudience1 = "URL";
_settings.IdConfiguration = new IdConfiguration();
_settings.IdConfiguration.ClientId = "clientid"; 
_settings.IdConfiguration.RsaPrivateKeyJwk = new TestIT.Authenticator.API.Helpers.SecurityKey("{'d':'XXXXXX','kid':'XXXXXX','use':'XXXXX','alg':'XXXXX'}", "XXXXX");
_settings.IdConfiguration.Scope = "scope";
_settings.IdConfiguration.StsUrl = "URL";

builder.Services.AddHttpContextAccessor();

builder.Services.AddMvc()
    .AddJsonOptions(options =>
    {
        options.JsonSerializerOptions.PropertyNamingPolicy = new LowercaseContractResolver();
        options.JsonSerializerOptions.PropertyNameCaseInsensitive = true;
        options.JsonSerializerOptions.Converters.Add(new TestIT.Authenticator.API.Helpers.DateTimeHelper("dd.MM.yyyyTHH.mm.ss"));
    })
    .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix, opts =>
    {
        opts.ResourcesPath = "Resources";
    })
    .AddDataAnnotationsLocalization();

builder.Services.AddControllers();
builder.Services.AddRouting(options => options.LowercaseUrls = true);
builder.Services.AddEndpointsApiExplorer();
builder.Services.Configure<CookiePolicyOptions>(options =>
{
    options.MinimumSameSitePolicy = SameSiteMode.None;
    options.Secure = CookieSecurePolicy.Always; // Ensure cookies are marked as Secure
});

// Create a settings instance. These can be injected into other objects, for instance the HomeController 
builder.Services.AddSingleton<Settings>(_settings);
// We need the IdConfiguration instance as a service as well:
builder.Services.AddSingleton<IdConfiguration>(_settings.IdConfiguration);


// Services for calculating the expiration time for tokens
var dateTimeService = new DateTimeService();
builder.Services.AddSingleton<IDateTimeService>(dateTimeService);
builder.Services.AddTransient<IExpirationTimeCalculator, ExpirationTimeCalculator>();
builder.Services.AddSingleton<IHelseServices, HelseServices>();



// No request object is needed, so we inject a null object for payload claims creation instead
builder.Services.AddSingleton<IPayloadClaimsCreatorForRequestObjects>(new NullPayloadClaimsCreatorForRequestObjects());

//var clientAssertionPayloadClaimsCreator = new ClientAssertionPayloadClaimsCreator(dateTimeService);
//builder.Services.AddSingleton<IPayloadClaimsCreatorForClientAssertion>(clientAssertionPayloadClaimsCreator);

var clientAssertionPayloadClaimsCreator = new ClientAssertionPayloadClaimsCreator(dateTimeService);


// We need payload claims for the token request, both the "default" type and for the multi-tenant organization number:
var compositePayloadClaimsCreator = new CompositePayloadClaimsCreator(new List<IPayloadClaimsCreator>
            {
                clientAssertionPayloadClaimsCreator,
                new PayloadClaimsCreatorForMultiTenantClient()
            });
// We add this object as an instance of IPayloadClaimsCreatorForClientAssertion
builder.Services.AddSingleton<IPayloadClaimsCreatorForClientAssertion>(compositePayloadClaimsCreator);

builder.Services.AddTransient<IJwtPayloadCreator, JwtPayloadCreator>();

builder.Services.AddSingleton<ISigningJwtTokenCreator, SigningJwtTokenCreator>();

builder.Services.AddTransient<IClientAssertionsBuilder, ClientAssertionsBuilder>();
// Builder for client assertions payloads
// Builder for JWT tokens used for client assertions
builder.Services.AddSingleton<IDiscoveryDocumentGetter>(new DiscoveryDocumentGetter(_settings.IdConfiguration.StsUrl));
builder.Services.AddSingleton<IIdEndpointsDiscoverer, IdEndpointsDiscoverer>();
// Builds token requests (in our case, refresh token requests)
builder.Services.AddTransient<ITokenRequestBuilder, TokenRequestBuilder>();
// Register services here

builder.Services.AddTransient<IAccessTokenUpdater, AccessTokenUpdaterForMultiTenantRequests>();
builder.Services.AddScoped<IUserSessionDataStore, MemoryUserSessionDataStore>();
// A getter of user session data, uses the user session data store
builder.Services.AddTransient<IUserSessionGetter, UserSessionGetter>();


builder.Services.AddAuthentication(options =>
{
    // Configure default authentication schemes for the application
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    //options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
    .AddJwtBearer(options =>
    {
        // Configure JWT bearer authentication
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuerSigningKey = true,
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(config.GetValue<string>("Secret"))),
            ValidateIssuer = true,
            ValidIssuer = config.GetValue<string>("Issuer"),
            ValidateAudience = true,
            ValidAudience = config.GetValue<string>("Audience"),
            ValidateLifetime = true,
        };
    });

builder.Services.AddSwaggerGen(c =>
{
    // Configure Swagger documentation
    c.SwaggerDoc("v1", new OpenApiInfo { Title = "TestIt .Net middleware", Version = "v1" });

    // Add JWT bearer authentication to Swagger
    var securityScheme = new OpenApiSecurityScheme
    {
        Name = "Authorization",
        BearerFormat = "JWT",
        Scheme = "bearer",
        Description = "JWT Authorization header using the Bearer scheme.",
        In = ParameterLocation.Header,
        Type = SecuritySchemeType.Http,
    };
    c.AddSecurityDefinition("Bearer", securityScheme);
    c.AddSecurityRequirement(new OpenApiSecurityRequirement
    {
        {
            new OpenApiSecurityScheme
            {
                Reference = new OpenApiReference
                {
                    Type = ReferenceType.SecurityScheme,
                    Id = "Bearer"
                }
            },
            Array.Empty<string>()
        }
    });
});

builder.Services.ConfigureApplicationCookie(options =>
{
    options.Cookie.HttpOnly = true;
    options.Cookie.SecurePolicy = CookieSecurePolicy.Always; // Ensure cookies are sent over HTTPS
    options.Cookie.SameSite = SameSiteMode.None; // Set the SameSite attribute to None
});



builder.Services.AddTransient<IConfigureOptions<AuthenticationOptions>, AuthenticationOptionsInitializer>();
builder.Services.AddTransient<IConfigureNamedOptions<OpenIdConnectOptions>, UserAuthendication>();
builder.Services.AddTransient<AuthenticationsController>();
builder.Services.Configure<CookiePolicyOptions>(OpenIdConnectOptions =>
{
    OpenIdConnectOptions.MinimumSameSitePolicy = SameSiteMode.None;
    OpenIdConnectOptions.Secure = CookieSecurePolicy.Always; // Ensure cookies are marked as Secure
});
//// Set authentication options (these will call the AuthenticationOptionsInitializer and OpenIdConnectOptionsInitializer instances)
builder.Services.AddAuthentication()
    .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, OpenIdConnectOptions =>
    {
        // Path to access denied endpoint. Used when authorization fails
        OpenIdConnectOptions.AccessDeniedPath = "/authorization/access-denied";
        OpenIdConnectOptions.AccessDeniedPath = "/authorization/access-denied";

        // Ensure cookies are only sent over HTTPS
        OpenIdConnectOptions.Cookie.SecurePolicy = CookieSecurePolicy.Always;

        // Set SameSite policy. Adjust as necessary based on your requirements
        OpenIdConnectOptions.Cookie.SameSite = SameSiteMode.None;

        // Mark the cookie as HttpOnly
        OpenIdConnectOptions.Cookie.HttpOnly = true;
    })
    .AddOpenIdConnect(openIdConnectOptions =>
    {
        // We need to extract the OpenID Connect options initializer from the service provider:
        var serviceProvider = builder.Services.BuildServiceProvider();
        var initializer = serviceProvider.GetService<IConfigureNamedOptions<OpenIdConnectOptions>>();
        initializer!.Configure(nameof(UserAuthendication), openIdConnectOptions);
        openIdConnectOptions.CallbackPath = "/signin-oidc";
        openIdConnectOptions.NonceCookie.SecurePolicy = CookieSecurePolicy.Always;
        openIdConnectOptions.CorrelationCookie.SecurePolicy = CookieSecurePolicy.Always;
       
    });



var securityLevelClaimPolicy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .RequireClaim(IdSecurityLevelClaim, "4")
        .Build();



builder.Services.AddDataProtection();
builder.Services.AddAuthorization(config =>
{
    config.AddPolicy(SecurityLevelClaimPolicy, securityLevelClaimPolicy);
});
var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}
else
{
    app.UseExceptionHandler("/Error");
    
}

app.UseRouting();

app.UseForwardedHeaders(new ForwardedHeadersOptions
{
    ForwardedHeaders = Microsoft.AspNetCore.HttpOverrides.ForwardedHeaders.XForwardedFor | Microsoft.AspNetCore.HttpOverrides.ForwardedHeaders.XForwardedProto
});
app.UseCookiePolicy(new CookiePolicyOptions
{
    Secure = CookieSecurePolicy.Always,
   
});




// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}







//app.UseHttpsRedirection();




app.UseCors("AllowAll");
app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();

app.Run();

Is there something I’m missing in the configuration that could be causing the correlation cookies to be lost after authentication? Any advice or insights would be greatly appreciated.

New contributor

Halvar is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.

0

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật