Post

BFF + OIDC Cookie: when Nginx silently kills the TLS connection

BFF + OIDC Cookie: when Nginx silently kills the TLS connection

Context

Migrating a Blazor WASM application from client-side OIDC authentication (oidc-client-ts + JWT Bearer) to a BFF (Backend For Frontend) pattern: the ASP.NET Core server handles the full OIDC flow, the client receives an HttpOnly session cookie.

The stack:

  • Blazor WASM (client) behind ASP.NET Core (server)
  • Logto as identity provider (OIDC)
  • Nginx as reverse proxy (Jelastic Cloud / Infomaniak)
  • Session cookie via AddCookie() + AddOpenIdConnect() server-side

The symptom

After deploying the BFF, authentication works fine on the Logto side (login OK), but when redirecting back to the application:

Secure Connection Failed

The connection to app.example.com was interrupted while the page was loading. The page you are trying to view cannot be shown because the authenticity of the received data could not be verified.

The error only appears after authentication. Unauthenticated pages (/health, static files) work perfectly. The TLS certificate is valid.

The investigation

What works

  • Private browsing without authentication: OK
  • /health endpoint: OK
  • SSL certificate: valid (Let’s Encrypt, 2 months until expiry)
  • ASPNETCORE_FORWARDEDHEADERS_ENABLED=true: properly configured

What breaks

  • Any navigation after the session cookie is issued
  • The redirect from Logto to /signin-oidc

The culprit: large_client_header_buffers

The default Jelastic Nginx configuration:

1
2
client_header_buffer_size 1k;
large_client_header_buffers 4 2k;

The problem becomes obvious when you know that Nginx’s default value is 4 8k (official documentation). Jelastic reduced this to 4 2k in their default configuration - four times smaller than the standard value.

This is a well-known issue in environments where Nginx acts as a reverse proxy in front of applications with cookie-based authentication. JWT tokens alone can be 1-2 KB, and with OIDC session cookies, state parameters, and CSRF tokens, header size quickly spirals out of control (source).

With the BFF pattern, the ASP.NET Core session cookie contains:

  • Encrypted user claims (sub, email, name, roles)
  • Session metadata (expiration, sliding window)
  • With SaveTokens = true: OIDC tokens (access + id + refresh) - easily 2-3 KB more

The encrypted cookie easily exceeds 2 KB. But Nginx is configured with header buffers of 2 KB max (instead of the standard 8 KB). When the browser sends the cookie on the next request, Nginx kills the TLS connection before forwarding to the backend. No error log on the application side, no HTTP status code - just a broken TLS connection that the browser interprets as a security error.

Typically, when buffers are exceeded, Nginx returns a 400 Bad Request: Request Header or Cookie Too Large error. But in our case, the TLS connection is severed before Nginx can send an HTTP response - hence the misleading security error in the browser.

The fix

1. Increase Nginx header buffers

In nginx-jelastic.conf (inside the http block):

1
2
3
4
5
# Before (Jelastic default - 4x smaller than Nginx's default!)
large_client_header_buffers 4 2k;

# After - restoring Nginx's default, sufficient for OIDC session cookies
large_client_header_buffers 4 8k;

Restart Nginx after the change.

Note: 4 8k is Nginx’s default value. Some configurations even recommend 4 16k for applications with complex SSO (DigitalOcean). Memory is only allocated when headers exceed the client_header_buffer_size (1 KB), so the impact is negligible.

Disable SaveTokens if tokens aren’t needed server-side after authentication:

1
2
3
4
5
.AddOpenIdConnect(options =>
{
    // ...
    options.SaveTokens = false; // don't store tokens in the cookie
});

With BFF, tokens are typically only useful during the authentication flow (code exchange → tokens → claims). Once claims are extracted and stored in the session cookie, raw tokens are no longer needed - unless you need to call third-party APIs with the access token.

For cases where the cookie still exceeds 4 KB, ASP.NET Core can split it into multiple chunks automatically. But it’s better to reduce the size upfront.

Why this problem didn’t exist before

With client-side JWT Bearer authentication:

  • The JWT was sent in the Authorization: Bearer xxx header
  • The browser sent no authentication cookie
  • Request headers stayed small

With BFF + Cookie:

  • The session cookie is sent on every same-origin request
  • Header size increases significantly
  • Nginx configurations with restrictive buffers (< 4 KB) break silently

Summary

AspectDetail
SymptomTLS error after authentication, no HTTP error
Root causeNginx large_client_header_buffers too small for session cookie
Server fixlarge_client_header_buffers 4 8k; in Nginx
App fixSaveTokens = false to reduce cookie size
GotchaNo application-side logs - Nginx drops the connection before reaching the backend

References

This post is licensed under CC BY 4.0 by the author.