Post

BFF + Cookie OIDC : quand Nginx coupe la connexion TLS silencieusement

BFF + Cookie OIDC : quand Nginx coupe la connexion TLS silencieusement

Contexte

Migration d’une application Blazor WASM depuis une authentification OIDC côté client (oidc-client-ts + JWT Bearer) vers un pattern BFF (Backend For Frontend) : le serveur ASP.NET Core gère le flux OIDC complet, le client reçoit un cookie de session HttpOnly.

La stack :

  • Blazor WASM (client) derrière ASP.NET Core (serveur)
  • Logto comme fournisseur d’identité (OIDC)
  • Nginx en reverse proxy (Jelastic Cloud / Infomaniak)
  • Cookie de session AddCookie() + AddOpenIdConnect() côté serveur

Le symptôme

Après déploiement du BFF, l’authentification passe côté Logto (login OK), mais au retour sur l’application :

Échec de la connexion sécurisée

La connexion avec app.example.com a été interrompue pendant le chargement de la page. La page que vous essayez de consulter ne peut pas être affichée car l’authenticité des données reçues ne peut être vérifiée.

L’erreur apparaît uniquement après authentification. Les pages non authentifiées (/health, pages statiques) fonctionnaient parfaitement avant authentification. Le certificat TLS est valide.

L’investigation

Ce qui fonctionne

  • Navigation privée sans authentification : OK
  • Endpoint /health : OK
  • Certificat SSL : valide (Let’s Encrypt, expire dans 2 mois)
  • ASPNETCORE_FORWARDEDHEADERS_ENABLED=true : bien configuré

Ce qui ne fonctionne pas

  • Toute navigation après que le cookie de session soit émis
  • La redirection depuis Logto vers /signin-oidc

Le coupable : large_client_header_buffers

La configuration Nginx par défaut de Jelastic :

1
2
client_header_buffer_size 1k;
large_client_header_buffers 4 2k;

Le problème saute aux yeux quand on sait que la valeur par défaut de Nginx est 4 8k (documentation officielle). Jelastic a réduit cette valeur à 4 2k dans sa configuration par défaut - quatre fois moins que la valeur standard.

C’est un problème bien connu dans les environnements où Nginx sert de reverse proxy devant des applications avec authentification par cookie. Les JWT tokens seuls peuvent faire 1-2 Ko, et avec les cookies de session OIDC, les state parameters, les tokens CSRF, la taille des headers explose rapidement (source).

Avec le pattern BFF, le cookie de session ASP.NET Core contient :

  • Les claims utilisateur chiffrés (sub, email, name, roles)
  • Les métadonnées de session (expiration, sliding window)
  • Avec SaveTokens = true : les tokens OIDC (access + id + refresh) - facilement 2-3 Ko de plus

Le cookie chiffré dépasse facilement 2 Ko. Or Nginx est configuré avec des buffers de 2 Ko maximum (au lieu des 8 Ko standard). Quand le navigateur renvoie le cookie sur la requête suivante, Nginx coupe la connexion TLS avant de transmettre au backend. Pas de log d’erreur côté application, pas de code HTTP - juste une connexion TLS interrompue que le navigateur interprète comme une erreur de sécurité.

Habituellement, quand les buffers sont dépassés, Nginx retourne une erreur 400 Bad Request: Request Header or Cookie Too Large. Mais dans notre cas, la connexion TLS est coupée avant que Nginx puisse envoyer une réponse HTTP - d’où le message trompeur d’erreur de sécurité dans le navigateur.

La solution

1. Augmenter les buffers Nginx

Dans nginx-jelastic.conf (section http) :

1
2
3
4
5
# Avant (défaut Jelastic - 4x plus petit que le défaut Nginx !)
large_client_header_buffers 4 2k;

# Après - on restaure le défaut Nginx, suffisant pour les cookies de session OIDC
large_client_header_buffers 4 8k;

Redémarrer Nginx après la modification.

Note : 4 8k est la valeur par défaut de Nginx. Certaines configurations recommandent même 4 16k pour les applications avec SSO complexe (DigitalOcean). La mémoire n’est allouée que si les headers dépassent le client_header_buffer_size (1 Ko), donc l’impact est négligeable.

Désactiver SaveTokens si les tokens ne sont pas nécessaires côté serveur après l’authentification :

1
2
3
4
5
.AddOpenIdConnect(options =>
{
    // ...
    options.SaveTokens = false; // ne pas stocker les tokens dans le cookie
});

Avec le BFF, les tokens ne sont généralement utiles que pendant le flux d’authentification (échange code → tokens → claims). Une fois les claims extraites et stockées dans le cookie de session, les tokens bruts ne servent plus - sauf si on doit appeler des APIs tierces avec l’access token.

Pourquoi ce problème n’existait pas avant

Avec l’authentification JWT Bearer côté client :

  • Le token JWT était envoyé dans le header Authorization: Bearer xxx
  • Le navigateur n’envoyait aucun cookie d’authentification
  • Les headers restaient petits

Avec le BFF + Cookie :

  • Le cookie de session est envoyé sur chaque requête same-origin
  • La taille des headers augmente significativement
  • Les configurations Nginx avec des buffers restrictifs (< 4 Ko) cassent silencieusement

Résumé

AspectDétail
SymptômeErreur TLS après authentification, pas d’erreur HTTP
Causelarge_client_header_buffers Nginx trop petit pour le cookie de session
Fix serveurlarge_client_header_buffers 4 8k; dans Nginx
Fix applicatifSaveTokens = false pour réduire la taille du cookie
PiègeAucun log côté application - Nginx coupe avant le backend

Références

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