The flagship 5-line-integration example. It shows how securityhttp.NewHandler
assembles the entire security middleware chain — secure headers,
session-backed authentication, CSRF, default-deny authorization, and a JSON
login endpoint — around a plain application handler, with secure defaults and
fail-loud validation.
The five lines
CSRF is on by default (synchronizer token, session-backed), security headers
are on, the session cookie is Secure+HttpOnly+SameSite=Lax, and
authorization is default-deny (AnyRequest().Authenticated()) — none of
which the integrator has to remember to enable.
Full source
The example listens on :8443 (see http.ListenAndServe(":8443", handler)),
served over plain HTTP for local testing — no TLS certificate is configured
in this example. Because the session cookie defaults to Secure, a browser
will not send it back over plain HTTP; use curl, which doesn’t enforce that,
or configure TLS termination for a real deployment.
Trying it out
Verified by running the example: that second command returns 403, not a
successful login. WithAuthorize() here is AnyRequest().Authenticated() with no
PermitAll carve-out for /login, and CSRF defaults to the session-backed
synchronizer token — but nothing in this exact five-line configuration ever
creates a session or issues a token before login, because every anonymous
request (including GET / and GET /login) is already denied by the authz
leg. There is no bare-curl path through this literal configuration that
reaches the login handler.To see the chain’s pieces work end-to-end against real HTTP requests, use
examples/playground or
examples/webapp instead — both add an explicit
PermitAll (or an unguarded mux) for the login path, and playground pairs it
with a double-submit CSRF repository that doesn’t need a pre-existing
session. To exercise this exact configuration, either add
authz.Match("/login").PermitAll() to authz.Routes(...), or see
securityhttp_test.go’s TestIntegration_CookieSecureDefaults, which drives
the login handler directly with securityhttp.CSRFDisabled() and
securityhttp.AllowLoginWithoutCSRF().
Once a session exists (e.g. by adjusting the authorize rules as above, or in
a test that seeds one directly), the rest of the chain behaves as documented:
What you get for free
X-Content-Type-Options: nosniff, X-Frame-Options: DENY, and the other
security-header defaults on every response
- Session cookie with
Secure; HttpOnly; SameSite=Lax
- CSRF synchronizer token (session-backed) protecting every unsafe request
- Default-deny authorization:
AnyRequest().Authenticated() means an
unmatched path requires a session, not open access
- Session fixation protection: the session ID rotates on login
- Fail-loud assembly:
New() or NewHandler() — a misconfigured chain
(e.g. no terminal authorization rule) errors at startup, not at request time