App Logo
Plugins

CSRF Plugin

Server-side protection against Cross-Site Request Forgery attacks using the Double-Submit Cookie pattern

Overview

The CSRF plugin provides server-side protection against Cross-Site Request Forgery (CSRF) attacks using the Double-Submit Cookie pattern integrated into Authula's lifecycle hook system. It automatically generates cryptographically secure tokens for safe HTTP methods and validates them on state-changing requests.

Features

  • Double-Submit Cookie Pattern — Validates CSRF tokens in both cookies and request headers
  • Automatic Token Generation — Generates secure tokens on safe HTTP methods (GET, HEAD, OPTIONS)
  • Selective Enforcement — Only validates on routes that explicitly request protection
  • Token Cleanup — Automatically clears CSRF cookies on sign-out
  • Optional Header Protection — Supports Go 1.25's CrossOriginProtection for additional security

Configuration

Standalone Mode

[plugins.csrf]
enabled = true
cookie_name = "authula_csrf_token"
header_name = "X-AUTHULA-CSRF-TOKEN"
max_age = "24h"
secure = true
same_site = "lax"
enable_header_protection = false

Library Mode

import (
	csrfplugin "github.com/Authula/authula/plugins/csrf"
)

csrfplugin.New(csrfplugin.CSRFPluginConfig{
	Enabled:                true,
	CookieName:             "authula_csrf_token",
	HeaderName:             "X-AUTHULA-CSRF-TOKEN",
	MaxAge:                 24 * time.Hour,
	Secure:                 false,
	SameSite:               "lax",
	EnableHeaderProtection: false,
}),

Configuration Options

OptionTypeDefaultDescription
enabledbooleantrueEnable or disable the plugin
cookie_namestring"authula_csrf_token"Name of the CSRF cookie
header_namestring"X-AUTHULA-CSRF-TOKEN"Name of the CSRF header
max_ageduration"24h"Token lifetime before expiration
securebooleanfalseForce Secure flag on cookies
same_sitestring"lax"SameSite attribute: lax, strict, or none
enable_header_protectionbooleanfalseEnable Go's CrossOriginProtection

API Reference

The CSRF plugin doesn't expose any HTTP endpoints.


Database Schema

The CSRF plugin doesn't create any database tables.


Plugin Capabilities

The CSRF plugin integrates with Authula through the lifecycle hook system, registering hooks at specific stages:

  • Before Hook (Order 5) — Token generation for safe methods (GET, HEAD, OPTIONS)
  • Before Hook (Order 5) — Token validation for unsafe methods (POST, PUT, PATCH, DELETE) — requires explicit opt-in via route metadata
  • After Hook (Order 5) — Cookie cleanup on sign-out

It also has the following capabilities:

  • csrf.protect — Validates the presence and correctness of CSRF tokens on protected routes

Token Generation Flow

On safe HTTP methods, the plugin automatically generates a cryptographically secure token and sets it as a cookie. The cookie is intentionally readable by JavaScript (HttpOnly=false) to enable the Double-Submit pattern.

Token Validation Flow

On state-changing methods, the plugin validates that the CSRF token exists in both:

  1. A cookie (readable by JavaScript)
  2. A request header

Both values must match exactly. Requests with missing or mismatched tokens are rejected with a 403 Forbidden response.

Optional Layered Protection

Beyond the Double-Submit pattern, the plugin optionally supports header-based origin validation using Go 1.25's CrossOriginProtection. When enabled via enable_header_protection, this validates Sec-Fetch-Site, Origin, and Host headers against configured trusted origins before token validation occurs.

How to Use

Routes must explicitly request CSRF protection by including the plugin identifier in their metadata. This allows selective protection—authentication endpoints like sign-in can skip validation while authenticated endpoints enforce it.

[[route_mappings]]
method = "POST"
path = "/some/path"
plugins = ["csrf.protect"]

Client Plugin

If you're using the Authula SDK, add the plugin to the SDK like so:

import { createClient } from "authula";
import { CSRFPlugin } from "authula/plugins";

export const authulaClient = createClient({
  url: "http://localhost:8080/auth",
  plugins: [
    // other plugins...
    new CSRFPlugin({
      cookieName: "authula_csrf_token", // optional, defaults to "authula_csrf_token"
      headerName: "X-AUTHULA-CSRF-TOKEN", // optional, defaults to "X-AUTHULA-CSRF-TOKEN"
    }),
  ],
});

Key Design Decisions

  • HttpOnly=false — Required for Double-Submit pattern where JavaScript must read the cookie value
  • Selective enforcement — Only validates on routes that explicitly request protection
  • Defense in depth — Optional header protection provides additional layer beyond tokens
  • Hot reloadable — Configuration changes apply without server restart

Security Recommendations

  • Enable Secure Flag in Production — Set secure = true to ensure cookies are only transmitted over HTTPS
  • Strict SameSite — Set same_site = "strict" for maximum CSRF protection if you need it (may impact UX). But you may want to keep it at lax to still allow some cross-site requests especially for top-level navigations.
  • Enable Header Protection — Consider enabling enable_header_protection = true for additional origin validation
  • Trusted Origins — When using header protection, configure trusted origins appropriately for your deployment
  • Token Rotation — The 24-hour default max_age provides a balance between security and UX; adjust based on your security requirements
  • HttpOnly Trade-off — The Double-Submit pattern requires HttpOnly=false, making tokens accessible to JavaScript; ensure your application is protected against XSS attacks

On this page