title: Authentication cookie disappears in react SPA after some time
body: <p>We have an SPA, written in React together with ASP.net core for hosting.</p>
  <p>To authenticate the app, we are using IdentityServer4 and use a cookie. The client is configured according to the sample, described here: <a href="https://github.com/IdentityServer/IdentityServer4/tree/main/samples/Quickstarts/4_JavaScriptClient/src" rel="noreferrer">https://github.com/IdentityServer/IdentityServer4/tree/main/samples/Quickstarts/4_JavaScriptClient/src</a></p>
  <p>For authenticating a user, everythings works fine. It will be redirected to the login page. After signing in, redirection to the SPA is done. The authentiation cookie is set as expected with:</p>
  <ul>
  <li>HttpOnly = true</li>
  <li>Secure = true</li>
  <li>SameSite = None</li>
  <li>Expires / Max-age = one week from login time</li>
  </ul>
  <p>The cookie is used also in other MVC (.net core and MVC 5) applications for authentication reasons.
  In the SPA, we are also using SignalR, which needs the cookie for authentication.</p>
  <p><strong>Our issue:</strong></p>
  <p>After about 30 minutes of idle time in the browser and either doing a refresh or navigating, the authentication cookie (and only that, other remains) is disappearing from the browser automatically. Then the user has to sign in again. Why does this happen together with the SPA?</p>
  <p><strong>Code</strong></p>
  <p>Complete code can be found in <a href="https://github.com/wedge76/AuthenticationIssues" rel="noreferrer">github</a></p>
  <p><em>Client</em></p>
  <p>Snippets of <code>UserService.ts</code></p>
  <pre><code>const openIdConnectConfig: UserManagerSettings = {
    authority: baseUrls.person,
    client_id: &quot;js&quot;,
    redirect_uri: joinUrl(baseUrls.spa, &quot;signincallback&quot;),
    response_type: &quot;code&quot;,
    scope: &quot;openid offline_access profile Person.Api Translation.Api&quot;,
    post_logout_redirect_uri: baseUrls.spa,
    automaticSilentRenew: true
  };
  
  export const getUserService = asFactory(() =&gt; {
    const userManager = new UserManager(openIdConnectConfig);
    return createInstance(createStateHandler(defaultUserState), userManager, createSignInProcess(userManager));
  }, sameInstancePerSameArguments());
  </code></pre>
  <p><em>Server</em></p>
  <p>Snipped of <code>Startup.cs</code></p>
  <pre><code>public void ConfigureServices(IServiceCollection services)
  {
      Log.Information($&quot;Start configuring services. Environment: {_environment.EnvironmentName}&quot;);
      services.AddControllersWithViews();
  
      services.AddIdentity&lt;LoginInputModel, RoleDto&gt;()
              .AddDefaultTokenProviders();
  
      var certificate = LoadSigningCertificate();
      var identityServerBuilder = services.AddIdentityServer(options =&gt;
                                                             {
                                                                 options.Events.RaiseErrorEvents = true;
                                                                 options.Events.RaiseInformationEvents = true;
                                                                 options.Events.RaiseFailureEvents = true;
                                                                 options.Events.RaiseSuccessEvents = true;
                                                             })
                                          .AddSigningCredential(certificate)
                                          .AddProfileService&lt;ProfileService&gt;()
                                          .AddInMemoryIdentityResources(Config.Ids)
                                          .AddInMemoryApiResources(Config.Apis)
                                          .AddInMemoryClients(new ClientConfigLoader().LoadClients(Configuration));
  
      if (_environment.IsDevelopment())
      {
          identityServerBuilder.AddDeveloperSigningCredential();
      }
  
      services.Configure&lt;CookiePolicyOptions&gt;(options =&gt;
                                              {
                                                  options.CheckConsentNeeded = context =&gt; false;
                                                  options.MinimumSameSitePolicy = SameSiteMode.None;
                                              });
  
      services.AddDataProtection()
              .PersistKeysToFileSystem(new DirectoryInfo(_sharedAuthTicketKeys))
              .SetApplicationName(&quot;SharedCookieApp&quot;);
  
      services.AddAsposeMailLicense(Configuration);
      var optionalStartupSettings = SetupStartupSettings();
      if (optionalStartupSettings.IsSome)
      {
          var settings = optionalStartupSettings.Value;
  
          services.ConfigureApplicationCookie(options =&gt;
                                              {
                                                  options.AccessDeniedPath = new PathString(&quot;/Account/AccessDenied&quot;);
                                                  options.Cookie.Name = &quot;.AspNetCore.Auth.Cookie&quot;;
                                                  options.Cookie.Path = &quot;/&quot;;
                                                  options.Cookie.HttpOnly = true;
                                                  options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
                                                  options.LoginPath = new PathString(&quot;/account/login&quot;);
                                                  options.Cookie.SameSite = SameSiteMode.None;
                                              });
  
          var authBuilder = services.AddAuthentication(options =&gt; { options.DefaultAuthenticateScheme = &quot;Identity.Application&quot;; });
          authBuilder = ConfigureSaml2(authBuilder, settings);
          authBuilder = ConfigureGoogle(authBuilder);
          authBuilder.AddCookie();
      }
      else
      {
          throw new InvalidOperationException($&quot;Startup settings are not configured in appsettings.json.&quot;);
      }
  
      SetupEntityFramework(services);
  }
  
  </code></pre>
  <p>Snippet of identity server client config from <code>appsettings.json</code></p>
  <pre><code>{
      &quot;Enabled&quot;: true,
      &quot;ClientId&quot;: &quot;js&quot;,
      &quot;ClientName&quot;: &quot;JavaScript Client&quot;,
      &quot;AllowedGrantTypes&quot;: [ &quot;authorization_code&quot; ],
      &quot;RequirePkce&quot;: true,
      &quot;RequireClientSecret&quot;: false,
      &quot;RedirectUris&quot;: [ &quot;https://dev.myCompany.ch/i/signincallback&quot;, &quot;https://dev.myCompany.com/i/signincallback&quot;, &quot;https://dev.myCompany.de/i/signincallback&quot; ],
      &quot;PostLogoutRedirectUris&quot;: [ &quot;https://dev.myCompany.ch/i/&quot;, &quot;https://dev.myCompany.com/i/&quot;, &quot;https://dev.myCompany.de/i/&quot; ],
      &quot;AllowedCorsOrigins&quot;: [],
      &quot;AllowedScopes&quot;: [ &quot;openid&quot;, &quot;offline_access&quot;, &quot;profile&quot;, &quot;Translation.Api&quot;, &quot;Person.Api&quot; ],
      &quot;RequireConsent&quot;: false,
      &quot;AllowOfflineAccess&quot;: true
  }
  
  </code></pre>
  <p><strong>Update</strong></p>
  <p>In the meantime I discovered that the cookie, while requesting <code>https://ourdomain/.well-known/openid-configuration</code> after 30 minutes idle time, has lost the values of <em>Domain, Path, Expires/Max-Age, HttpOnly, Secure and SameSite.None</em>. Those values have definitely been set after signing in.
  The response cookie has the value of <em>Expires/Max-Age</em> set to a time in the past and therefore the cookie will be dropped by the browser.
  <a href="https://i.stack.imgur.com/No1yH.png" rel="noreferrer"><img src="https://i.stack.imgur.com/No1yH.png" alt="Network traffic" /></a></p>
  <p>Has anyone an idea, why those values got lost after some time?</p>