CSRF Protection
Overview
CSRF (Cross-Site Request Forgery) protection is built into Lemmego through the middleware.VerifyCSRF middleware. It uses a double-submit cookie pattern with session-based tokens.
How It Works
- For every GET request, a random token is generated and stored in the session
- The token is also set as an
XSRF-TOKENcookie - For state-changing requests (POST, PUT, PATCH, DELETE), the middleware compares the token from the request with the one in the session
- Comparison uses constant-time comparison to prevent timing attacks
- On successful validation, the token is rotated (new token generated)
CSRF Token Sources
The middleware checks for the token in this order:
X-XSRF-TOKENheader_tokenPOST form value_tokenquery parameter- JSON body
_tokenfield
Configuration
middleware.VerifyCSRF(&middleware.CSRFOpts{
ExcludePatterns: []string{"/api/.*", "/webhook"},
})Excluded patterns are evaluated as regular expressions. Requests matching any pattern skip CSRF verification entirely.
In Templates
Go Templates
The _token is available in templates via session data:
<form method="POST" action="/tasks">
<input type="hidden" name="_token" value="{{ .csrf_token }}">
</form>Templ
A helper component is provided:
templ CsrfField() {
<input type="hidden" name="_token" value={ templ.Raw(csrf.Token) }/>
}Usage:
<form method="POST" action="/tasks">
@CsrfField()
</form>Inertia
CSRF tokens are automatically included in Inertia requests through the XSRF-TOKEN cookie.
API Routes
For JSON API routes, exclude CSRF verification:
middleware.VerifyCSRF(&middleware.CSRFOpts{
ExcludePatterns: []string{"/api/.*"},
})API clients should use token-based authentication (JWT or API keys) instead.
Security Notes
- Tokens are generated using
crypto/randfor cryptographic security - Token comparison uses
subtle.ConstantTimeCompareto prevent timing side-channels - Tokens are rotated after each successful validation (prevents token reuse)
- The session token is separate from the cookie token for defense in depth