title: C# (dotnet core) Correlation failed. Behind ingress (GLBC) loadbalancer on GKE
body: <p>I have struggling with authentication now for weeks on a project, and it's killing me. Bear with me, this is my first post on stackoverflow as well. </p>
  
  <p>I have been looking around and googling/searching here on stackoverflow, and have come up with some different things but none seem to help: </p>
  
  <ul>
  <li>Host ASP.NET Core in a web farm (<a href="https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/web-farm?view=aspnetcore-2.1" rel="nofollow noreferrer">https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/web-farm?view=aspnetcore-2.1</a>)</li>
  <li>Configure ASP.NET Core to work with proxy servers and load balancers (<a href="https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer?view=aspnetcore-2.1" rel="nofollow noreferrer">https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer?view=aspnetcore-2.1</a>)</li>
  <li>Similar github issue (<a href="https://github.com/aspnet/Security/issues/1755#issuecomment-392803709" rel="nofollow noreferrer">https://github.com/aspnet/Security/issues/1755#issuecomment-392803709</a>)</li>
  </ul>
  
  <p>My Microsoft Azure authentication has the same problem, and is based off: 
  <a href="https://github.com/microsoftgraph/aspnetcore-connect-sample" rel="nofollow noreferrer">https://github.com/microsoftgraph/aspnetcore-connect-sample</a></p>
  
  <p>Stacktrace: </p>
  
  <pre><code>[09:58:48 INF] Error from RemoteAuthentication: Correlation failed..
  [09:58:48 ERR] An unhandled exception has occurred while executing the request.
  System.Exception: An error was encountered while handling the remote login. 
  ---&gt; System.Exception: Correlation failed.
  --- End of inner exception stack trace ---
  at Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler1.HandleRequestAsync() 
  at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context) 
  at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context) 
  at Muninn.Startup.&lt;&gt;c.&lt;&lt;Configure&gt;b__8_0&gt;d.MoveNext() 
  in /Muninn/Startup.cs:line 180 --- End of stack trace from previous location where exception was thrown --- 
  at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.Invoke(HttpContext context) 
  </code></pre>
  
  <p>This is the Startup.cs: 
      public class Startup
      {
          public Startup(IConfiguration configuration)
          {
              Configuration = configuration;
          }</p>
  
  <pre><code>    public IConfiguration Configuration { get; }
      public const string ObjectIdentifierType = "http://schemas.microsoft.com/identity/claims/objectidentifier";
      public const string TenantIdType = "http://schemas.microsoft.com/identity/claims/tenantid";
      public readonly IDataStore dataStore = new FileDataStore(GoogleWebAuthorizationBroker.Folder);
  
      // This method gets called by the runtime. Use this method to add services to the container.
      public void ConfigureServices(IServiceCollection services)
      {   
          services.AddDbContext&lt;ApplicationDbContext&gt;(options =&gt;
              options.UseNpgsql(Configuration.GetConnectionString("DefaultConnection")));
  
          services.AddIdentity&lt;ApplicationUser, IdentityRole&gt;()
              .AddEntityFrameworkStores&lt;ApplicationDbContext&gt;()
              .AddDefaultTokenProviders();
  
          services.AddAuthentication(sharedOptions =&gt;
          {
              sharedOptions.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
              sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
              sharedOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
          })
          .AddAzureAd(options =&gt; Configuration.Bind("AzureAd", options))
          .AddGoogle(googleOptions =&gt;
          {
              googleOptions.Scope.Add(CalendarService.Scope.Calendar);
              googleOptions.ClientId = Configuration["Google:ClientId"];
              googleOptions.ClientSecret = Configuration["Google:ClientSecret"];
              googleOptions.AccessType = "offline";
              googleOptions.SaveTokens = true;
              googleOptions.CallbackPath = "/signin-google";
              googleOptions.Events = new OAuthEvents()
              {
                  OnCreatingTicket = async (context) =&gt;
                  {
                      var userEmail = context.Identity.FindFirst(ClaimTypes.Email).Value;
                      Log.Information("New user logged in with Google: " + userEmail);
  
                      if(string.IsNullOrEmpty(context.AccessToken))
                          Log.Error("Access token was null");
                      if (string.IsNullOrEmpty(context.RefreshToken))
                          Log.Error("Refresh token was null");
  
                      var tokenResponse = new TokenResponse()
                      {      
                          AccessToken = context.AccessToken,
                          RefreshToken = context.RefreshToken,
                          ExpiresInSeconds = (long)context.ExpiresIn.Value.TotalSeconds,
                          IssuedUtc = DateTime.UtcNow
                      };
                      tokenResponse.Scope = CalendarService.Scope.Calendar;
                      await dataStore.StoreAsync(userEmail, tokenResponse);
                      Log.Information("User has been saved to the system: " + userEmail);
                  }
              };
          })
          .AddCookie(options =&gt;
          {
              options.LoginPath = "/Account/SignIn";
              options.LogoutPath = "/Account/SignOff";
          });
          services.AddMvc();
  
  
          var redis = ConnectionMultiplexer.Connect(Configuration["Redis:DefaultConnection"]);
          services.AddDataProtection()
              .PersistKeysToRedis(redis, "DataProtection-Keys")
              .SetApplicationName("myapp");
  
          services.AddDistributedRedisCache(options =&gt;
              {
                  options.Configuration = Configuration["Redis:DefaultConnection"];
                  options.InstanceName = "master";
              });
  
  
          services.Configure&lt;MvcOptions&gt;(options =&gt;
          {
              options.Filters.Add(new RequireHttpsAttribute());
          });
          services.Configure&lt;CookiePolicyOptions&gt;(options =&gt;
          {
              options.CheckConsentNeeded = context =&gt; false;
              options.MinimumSameSitePolicy = SameSiteMode.None;
          });
  
          services.AddSession(options =&gt;
          { 
              options.Cookie.Domain = ".myapp.com";
              options.Cookie.SecurePolicy = Microsoft.AspNetCore.Http.CookieSecurePolicy.Always;
              options.Cookie.Name = ".myapp.Session";
              options.IdleTimeout = TimeSpan.FromSeconds(5);
          });
  
          services.AddSingleton&lt;IGraphAuthProvider, GraphAuthProvider&gt;();
          services.AddTransient&lt;IGraphSdkHelper, GraphSdkHelper&gt;();
          services.AddTransient&lt;IEmailSender, EmailSender&gt;();
          services.AddTransient&lt;ICalendarActions, CalendarActions&gt;();
          services.AddTransient&lt;IOutlookCommunication, OutlookCommunication&gt;();
          services.Configure&lt;GoogleAuthOptions&gt;(Configuration.GetSection("Google"));
          services.AddTransient&lt;IGoogleCommunication, GoogleCommunication&gt;();
          services.Configure&lt;FormOptions&gt;(x =&gt;
          {
              x.ValueLengthLimit = int.MaxValue;
              x.MultipartBodyLengthLimit = int.MaxValue; // In case of multipart
          });
          services.AddAntiforgery();
  
      }
  
      // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
      public void Configure(IApplicationBuilder app, IHostingEnvironment env)
      {
          if (env.IsDevelopment())
          {
              app.UseDeveloperExceptionPage();
              app.UseBrowserLink();
              app.UseDatabaseErrorPage();                
          }
          else
          {
              app.UseExceptionHandler("/Home/Error");
          }
          app.UseForwardedHeaders(new ForwardedHeadersOptions
          {
              ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
          });
          app.Use(async (context, next) =&gt;
          {
              context.Request.Scheme = "https";
              await next.Invoke();
          });
          app.UseHttpsRedirection();
  
          var forceSSL = new RewriteOptions()
              .AddRedirectToHttps();
          app.UseRewriter(forceSSL);
  
          app.UseStaticFiles();
          app.UseAuthentication();
          app.UseSession();
          app.UseMvc(routes =&gt;
          {
              routes.MapRoute(
                  name: "default",
                  template: "{controller=Home}/{action=Index}/{id?}");
          });
      }
  }
  </code></pre>
  
  <p>This all runs in GKE as a deployment where the dockerfile is :</p>
  
  <pre><code>FROM microsoft/dotnet:2.1-sdk as builder
  COPY . .
  RUN dotnet restore &amp;&amp; dotnet build
  WORKDIR myapp
  RUN dotnet publish --output /app --configuration release -r ubuntu.16.04-x64
  
  FROM microsoft/dotnet:2.1-runtime
  EXPOSE 5000/tcp
  ENV ASPNETCORE_URLS http://*:5000
  COPY --from=builder /app .
  ENTRYPOINT dotnet myapp.dll  
  </code></pre>
  
  <p>I suspect the problem is that the google/azure endpoint's callback is not decrypted properly because my application does not realize it is being hosted in a "web farm" in Kubernetes despite my redis cache having "DataProtection-Keys" when I exec into the container. </p>
  
  <p>The application should also understand that its context is <a href="https://myapp.com" rel="nofollow noreferrer">https://myapp.com</a> since I set the ForwardHeaders bit.</p>
  
  <p>Help please..? </p>
  
  <p>tl;dr .NET core application behind GLBC gets "System.Exception: Correlation failed." despite using AddDataProtection() and Forwarded headers. I'm livid, please help. </p>