> ## Documentation Index
> Fetch the complete documentation index at: https://docs.go-mizu.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# CSRF2

> Enhanced CSRF protection with double submit cookie pattern.

## Overview

The `csrf2` middleware provides enhanced CSRF protection using the double submit cookie pattern, where a token is stored in both a cookie and must be submitted in a header or form field.

Use it when you need:

* Stateless CSRF protection
* Cookie-based token validation
* Enhanced security for SPAs

## Installation

```go theme={null}
import "github.com/go-mizu/mizu/middlewares/csrf2"
```

## Quick Start

```go theme={null}
app := mizu.New()

app.Use(csrf2.New(csrf2.Options{}))

app.Post("/submit", func(c *mizu.Ctx) error {
    return c.JSON(200, map[string]string{"status": "ok"})
})
```

## Configuration

### Options

| Option           | Type                    | Default                      | Description          |
| ---------------- | ----------------------- | ---------------------------- | -------------------- |
| `CookieName`     | `string`                | `"csrf_token"`               | Cookie name          |
| `HeaderName`     | `string`                | `"X-CSRF-Token"`             | Header name          |
| `FormField`      | `string`                | `"csrf_token"`               | Form field name      |
| `CookiePath`     | `string`                | `"/"`                        | Cookie path          |
| `CookieSecure`   | `bool`                  | `false`                      | HTTPS only           |
| `CookieSameSite` | `http.SameSite`         | `Lax`                        | SameSite policy      |
| `IgnoreMethods`  | `[]string`              | `["GET", "HEAD", "OPTIONS"]` | Methods to skip      |
| `ErrorHandler`   | `func(*mizu.Ctx) error` | -                            | Custom error handler |

## Examples

### Basic Usage

```go theme={null}
app.Use(csrf2.New(csrf2.Options{}))
```

### Secure Configuration

```go theme={null}
app.Use(csrf2.New(csrf2.Options{
    CookieName:     "_csrf",
    HeaderName:     "X-CSRF-Token",
    CookieSecure:   true,
    CookieSameSite: http.SameSiteStrictMode,
}))
```

### Custom Error Handler

```go theme={null}
app.Use(csrf2.New(csrf2.Options{
    ErrorHandler: func(c *mizu.Ctx) error {
        return c.JSON(403, map[string]string{
            "error": "Invalid CSRF token",
        })
    },
}))
```

### Get Token for Forms

```go theme={null}
app.Get("/form", func(c *mizu.Ctx) error {
    token := csrf2.Token(c)
    return c.HTML(200, `
        <form method="POST" action="/submit">
            <input type="hidden" name="csrf_token" value="`+token+`">
            <button type="submit">Submit</button>
        </form>
    `)
})
```

## How It Works

1. Middleware sets CSRF token in cookie
2. Client reads cookie and includes token in header/form
3. On state-changing requests, token is validated
4. If tokens match, request proceeds
5. If not, returns 403 Forbidden

## API Reference

### Functions

```go theme={null}
// New creates CSRF2 middleware
func New(opts Options) mizu.Middleware

// Token returns CSRF token from context
func Token(c *mizu.Ctx) string
```

## Client Implementation

### JavaScript (SPA)

```javascript theme={null}
// Read token from cookie
function getCsrfToken() {
    return document.cookie
        .split('; ')
        .find(row => row.startsWith('csrf_token='))
        ?.split('=')[1];
}

// Include in requests
fetch('/api/submit', {
    method: 'POST',
    headers: {
        'X-CSRF-Token': getCsrfToken(),
        'Content-Type': 'application/json'
    },
    body: JSON.stringify(data)
});
```

## Technical Details

### Token Generation

The middleware generates cryptographically secure tokens using the following process:

1. **Random Bytes**: Generates random bytes using `crypto/rand`
2. **Timestamp**: Appends current Unix timestamp for rotation support
3. **Signature**: Signs the token with SHA-256 using the provided secret
4. **Encoding**: Base64 URL-safe encoding for transport

### Token Validation

Token validation uses constant-time comparison to prevent timing attacks:

1. **Decode**: Both cookie and submitted tokens are base64-decoded
2. **Length Check**: Validates minimum token length (8 bytes)
3. **Constant-Time Compare**: Uses XOR-based comparison across all bytes
4. **Result**: Returns validation result without early exit

### Cookie Storage

Tokens are stored in HTTP cookies with configurable security options:

* **HttpOnly**: Default true to prevent JavaScript access
* **Secure**: Configurable for HTTPS enforcement
* **SameSite**: Default Lax mode for CSRF protection
* **MaxAge**: Default 24 hours (86400 seconds)
* **Path**: Default "/" for site-wide availability

### Token Retrieval

The middleware checks for tokens in the following order:

1. **Header**: Checks configured header name (default: `X-CSRF-Token`)
2. **Form**: Parses form data for configured field name (default: `_csrf`)
3. **Query**: Checks URL query parameters as fallback

### Origin Validation

When enabled, the middleware validates request origin:

1. **Origin Header**: Primary validation source
2. **Referer Fallback**: Used if Origin header is missing
3. **Allowed Origins**: Compares against configured whitelist
4. **Host Match**: Falls back to request host if no whitelist specified

### Advanced Features

* **Token Masking**: XOR-based masking for additional security
* **Fingerprinting**: SHA-256 hash of User-Agent and Accept headers
* **Form Input**: HTML helper for hidden form fields
* **Meta Tag**: HTML meta tag helper for SPAs

## Best Practices

* Always use HTTPS in production
* Use SameSite Strict for sensitive applications
* Include token in all state-changing requests
* Regenerate tokens on authentication changes

## Testing

### Test Coverage

| Test Case                 | Description                     | Expected Behavior                                               |
| ------------------------- | ------------------------------- | --------------------------------------------------------------- |
| `TestNew`                 | Basic middleware initialization | Creates middleware and sets CSRF cookie on GET request          |
| `TestGetToken`            | Token retrieval from context    | Token is stored in context and retrievable via `GetToken()`     |
| `TestValidateTokenHeader` | Token validation via header     | POST request with valid token in header succeeds (200 OK)       |
| `TestValidateTokenForm`   | Token validation via form field | POST request with valid token in form field succeeds (200 OK)   |
| `TestMissingToken`        | Request without CSRF token      | POST request without token returns 403 Forbidden                |
| `TestInvalidToken`        | Request with invalid token      | POST request with invalid token returns 403 Forbidden           |
| `TestSkipPaths`           | Path exclusion from validation  | Configured paths skip CSRF validation                           |
| `TestSkipMethods`         | HTTP method exclusion           | Safe methods (GET, HEAD, OPTIONS) skip validation               |
| `TestCustomErrorHandler`  | Custom error handling           | Custom error handler returns JSON response on failure           |
| `TestCustomCookieName`    | Custom cookie configuration     | CSRF cookie uses configured custom name                         |
| `TestCustomHeaderName`    | Custom header configuration     | Token validation accepts configured custom header name          |
| `TestTokenHandler`        | Token endpoint handler          | Token handler returns JSON with current CSRF token              |
| `TestFormInput`           | HTML form input helper          | Generates hidden input field with token value                   |
| `TestMetaTag`             | HTML meta tag helper            | Generates meta tag with csrf-token name and value               |
| `TestMaskUnmask`          | Token masking/unmasking         | Masked token differs from original, unmask restores original    |
| `TestFingerprint`         | Request fingerprinting          | Same headers produce same fingerprint, different headers differ |

## Related Middlewares

* [csrf](/middlewares/csrf) - Basic CSRF protection
* [session](/middlewares/session) - Session management
* [secure](/middlewares/secure) - Security settings
