Gateway and session
Blouppy.Gateway is the single origin the browser talks to. It serves the SPA, holds
the session, and forwards API calls with an access token — the
Backend-for-Frontend (BFF) pattern. The consequence that matters: no token ever
reaches JavaScript.
It is built from ASP.NET Core's own pieces — YARP, the cookie handler and Microsoft's OpenID Connect handler — with no BFF library.
What it does
| Concern | How |
|---|---|
| The session | A cookie (__Host-blouppy-gateway, SameSite=Strict, 8 hours sliding) holding the tokens. The cookie's encryption keys are in PostgreSQL (schema gateway), so a restart or a second replica keeps everyone signed in. |
| The access token | Attached to /api and /identity calls, refreshed a minute before it expires, one refresh at a time per session. A refused refresh ends the session. |
| CSRF | Every /api and /identity call must carry X-CSRF: 1, which a cross-site form cannot send. |
| The SPA's endpoints | /bff/login, /bff/logout (which revokes the refresh token), /bff/user for the signed-in user and the session's expiry. |
| The event stream | Proxied with response buffering off, and exempt from X-CSRF, since a browser EventSource cannot send a header. |
| Everything else | Proxied to the Angular app. |
Routes that are not the browser's
Two routes go through the gateway without the session:
/mcp— the MCP server. The client's own bearer goes through, the cookie is stripped and a foreignOriginrefused./scim/v2— an identity provider provisioning people, routed to the identity host.
Why it matters
A token in the browser can be read by any script that runs there — an injected one included. A cookie that JavaScript cannot read, scoped to one site, cannot be. The cost is one more service to run; see the choice for what you can change.