You check the “Remember me” or “Next time automatically sign me in” checkbox when logging in, but the next day (or even sooner) you are forced to log in again. This is one of the most common complaints in ASP.NET-based web applications, including Community Server, DotNetNuke, Orchard, and custom-built sites. The underlying causes are almost always related to cookie configuration, IIS behavior, or cryptographic key management.

This article explains how persistent authentication works in ASP.NET, what causes it to break, and how to fix it.

How “Remember Me” Authentication Works

ASP.NET Forms Authentication uses an encrypted cookie to identify authenticated users. When a user logs in, the server creates a FormsAuthenticationTicket, encrypts it using the machine key, and sends it to the browser as a cookie.

The login flow works as follows:

  1. User submits username, password, and checks “Remember me”
  2. Server validates credentials
  3. Server calls FormsAuthentication.SetAuthCookie(username, true) — the true parameter means “create a persistent cookie”
  4. The server generates a FormsAuthenticationTicket with an expiration date
  5. The ticket is encrypted using the machine key and written to the response as a cookie
  6. On subsequent requests, the browser sends the cookie; the server decrypts it and restores the user identity

The critical difference between a regular login and a “remember me” login is in step 3:

  • Without “remember me”: createPersistentCookie = false — the cookie has no Expires value, making it a session cookie that is deleted when the browser closes
  • With “remember me”: createPersistentCookie = true — the cookie is given an Expires value in the future, making it a persistent cookie that survives browser restarts

Common Causes of Persistent Login Failure

The timeout attribute in your web.config determines how long the authentication ticket is valid:

<authentication mode="Forms">
  <forms name=".ASPXAUTH"
         loginUrl="/login"
         timeout="30"
         slidingExpiration="true"
         protection="All"
         path="/" />
</authentication>

The timeout value is in minutes. A value of 30 means the cookie expires 30 minutes after it was issued (or last renewed, if slidingExpiration is true). For a “remember me” feature to last days or weeks, you need a much longer timeout:

<!-- Keep users logged in for 30 days -->
<forms name=".ASPXAUTH"
       loginUrl="/login"
       timeout="43200"
       slidingExpiration="true"
       protection="All"
       path="/" />

43200 minutes equals 30 days. With slidingExpiration="true", the cookie is renewed on each request if more than half the timeout period has elapsed, so active users will stay logged in indefinitely.

2. IIS Application Pool Recycling Invalidates Cookies

This is the most common and least obvious cause. By default, IIS recycles the application pool periodically (every 1740 minutes, or 29 hours). When the app pool recycles:

  • The ASP.NET worker process restarts
  • If the machine key is set to auto-generate (the default), a new key is generated
  • All previously issued authentication cookies, which were encrypted with the old key, can no longer be decrypted
  • Every user is effectively logged out

This is why users report being logged out “after about a day” — it coincides with the default app pool recycle interval.

The fix: set a static machine key in web.config.

<system.web>
  <machineKey
    validationKey="GENERATE_A_UNIQUE_64_BYTE_HEX_STRING_HERE"
    decryptionKey="GENERATE_A_UNIQUE_24_BYTE_HEX_STRING_HERE"
    validation="SHA1"
    decryption="AES" />
</system.web>

To generate proper keys, use IIS Manager:

  1. Open IIS Manager
  2. Select your site
  3. Double-click Machine Key
  4. Uncheck both “Automatically generate at runtime” checkboxes
  5. Click Generate Keys in the Actions panel
  6. Click Apply

This writes the keys into your web.config. As long as these keys remain the same, authentication cookies survive app pool recycles, server restarts, and even redeployments.

3. Load Balancer Routing to Different Servers

In a web farm or load-balanced environment, each server generates its own machine key by default. A cookie encrypted by Server A cannot be decrypted by Server B.

Symptoms include:

  • Users are randomly logged out during a single browsing session
  • The problem is intermittent and hard to reproduce
  • Checking server logs shows the authentication failure happening on a different server than the one that issued the cookie

The fix: use the same machine key on all servers. Copy the <machineKey> element from one server’s web.config to all other servers in the farm, or place it in machine.config at the framework level:

C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config\machine.config

If your site is accessible at both www.example.com and example.com, cookies set for one domain are not sent to the other. A user who logs in at www.example.com and then visits example.com will appear logged out.

Set an explicit cookie domain in web.config:

<forms name=".ASPXAUTH"
       loginUrl="/login"
       timeout="43200"
       domain=".example.com"
       path="/" />

The leading dot (.example.com) makes the cookie valid for the domain and all subdomains.

5. Secure Flag and HTTPS Mismatch

If the authentication cookie has the Secure flag set (meaning it should only be sent over HTTPS) but parts of your site are served over HTTP, the browser will not send the cookie on HTTP pages:

<httpCookies httpOnlyCookies="true" requireSSL="true" />

If requireSSL="true", make sure your entire site uses HTTPS. If you have mixed content, either enforce HTTPS everywhere (recommended) or set requireSSL="false".

The default cookie path is /, which means it is sent with every request to the domain. If the path is set to something more specific (like /app), requests to other paths will not include the cookie:

<!-- This is usually correct -->
<forms path="/" />

<!-- This would restrict the cookie to /myapp and its sub-paths -->
<forms path="/myapp" />

7. Browser Privacy Settings Blocking Cookies

Some users configure their browsers to delete cookies on exit, block third-party cookies, or use privacy extensions that interfere with persistent cookies. This is a client-side issue that cannot be fixed on the server.

To diagnose, ask the affected user to:

  1. Open browser developer tools (F12)
  2. Navigate to the Application (Chrome) or Storage (Firefox) tab
  3. Look for the authentication cookie under the site’s domain
  4. Check if the Expires column shows a future date or “Session”

If it shows “Session,” the “remember me” feature is not issuing a persistent cookie and the server-side code needs investigation.

Debugging Authentication Cookies

Using Browser Developer Tools

After logging in with “remember me” checked:

  1. Open developer tools (F12)
  2. Go to Application > Cookies (Chrome) or Storage > Cookies (Firefox)
  3. Find the .ASPXAUTH cookie (or whatever your forms auth cookie is named)
  4. Verify:
    • Expires: Should show a date far in the future (not “Session”)
    • Domain: Should match your site’s domain
    • Path: Should be / unless intentionally restricted
    • Secure: If true, verify you are on HTTPS
    • HttpOnly: Should be true (prevents JavaScript access)

Logging Authentication Events on the Server

Add logging to your Global.asax to track authentication events:

protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
    if (Context.User != null && Context.User.Identity.IsAuthenticated)
    {
        var identity = (FormsIdentity)Context.User.Identity;
        var ticket = identity.Ticket;
        System.Diagnostics.Debug.WriteLine(
            $"Auth: User={ticket.Name}, " +
            $"Issued={ticket.IssueDate}, " +
            $"Expires={ticket.Expiration}, " +
            $"Persistent={ticket.IsPersistent}");
    }
}

Check that IsPersistent is true when “remember me” was selected. If it is false, the application code is ignoring the checkbox value.

Checking IIS App Pool Recycle Times

To see when your app pool last recycled:

# PowerShell - check event logs for app pool recycles
Get-EventLog -LogName System -Source "WAS" -Newest 20 |
  Where-Object { $_.Message -like "*recycle*" } |
  Format-Table TimeGenerated, Message -AutoSize

If recycle times correlate with user logout reports and you do not have a static machine key configured, that is your root cause.

Complete Working Configuração

Here is a comprehensive web.config snippet that ensures persistent login works reliably:

<system.web>
  <authentication mode="Forms">
    <forms name=".MyAppAuth"
           loginUrl="/account/login"
           timeout="43200"
           slidingExpiration="true"
           protection="All"
           requireSSL="true"
           cookieless="UseCookies"
           domain=".example.com"
           path="/" />
  </authentication>

  <machineKey
    validationKey="your-64-byte-hex-validation-key"
    decryptionKey="your-24-byte-hex-decryption-key"
    validation="SHA1"
    decryption="AES" />
</system.web>

Key settings explained:

  • timeout=“43200”: 30-day cookie lifetime
  • slidingExpiration=“true”: Renews the cookie for active users
  • requireSSL=“true”: Only sends the cookie over HTTPS
  • cookieless=“UseCookies”: Never falls back to URL-based tokens
  • Static machineKey: Cookies survive app pool recycles and work across server farms

Modern ASP.NET Core Considerations

If you are building with ASP.NET Core, the configuration syntax is different but the same principles apply:

builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie(options =>
    {
        options.ExpireTimeSpan = TimeSpan.FromDays(30);
        options.SlidingExpiration = true;
        options.Cookie.HttpOnly = true;
        options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
        options.Cookie.SameSite = SameSiteMode.Lax;
    });

// For multi-server environments, configure Data Protection with shared key storage
builder.Services.AddDataProtection()
    .PersistKeysToFileSystem(new DirectoryInfo(@"\\shared\keys"))
    .SetApplicationName("MyApp");

In ASP.NET Core, Data Protection replaces the machine key system. All servers must share the same key ring, which can be stored on a shared network path, in Azure Blob Storage, or in a database.

Resumo

When “remember me” fails, work through this checklist:

  1. Check the forms authentication timeout — is it long enough for your use case?
  2. Set a static machine key — this is the fix for the majority of cases
  3. Verify cookie domain and path — make sure they match how users access your site
  4. Check HTTPS/Secure flag consistency — do not set requireSSL if you serve HTTP pages
  5. In load-balanced environments, share the machine key across all servers
  6. Inspect the cookie in the browser — confirm it has a future expiration date and the correct domain