> ## 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.

# Signature

> Request signature verification middleware for secure API access.

## Overview

The `signature` middleware verifies request signatures using HMAC or other algorithms, ensuring requests haven't been tampered with and come from authorized sources.

Use it when you need:

* Webhook signature verification
* API request authentication
* Tamper detection

## Installation

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

## Quick Start

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

// Verify HMAC-SHA256 signatures
app.Use(signature.New(signature.Options{
    Secret: []byte("your-secret-key"),
    Header: "X-Signature",
}))
```

## Configuration

### Options

| Option               | Type                     | Default         | Description           |
| -------------------- | ------------------------ | --------------- | --------------------- |
| `Secret`             | `[]byte`                 | Required        | Signing secret        |
| `Header`             | `string`                 | `"X-Signature"` | Signature header name |
| `Algorithm`          | `string`                 | `"sha256"`      | Hash algorithm        |
| `Encoding`           | `string`                 | `"hex"`         | Signature encoding    |
| `TimestampHeader`    | `string`                 | `""`            | Timestamp header      |
| `TimestampTolerance` | `time.Duration`          | `5m`            | Max timestamp age     |
| `GetSecret`          | `func(*mizu.Ctx) []byte` | -               | Dynamic secret lookup |

## Examples

### Basic HMAC Verification

```go theme={null}
app.Use(signature.New(signature.Options{
    Secret: []byte("webhook-secret"),
    Header: "X-Signature",
}))
```

### GitHub Webhook

```go theme={null}
app.Post("/webhook/github", handler, signature.New(signature.Options{
    Secret:   []byte(os.Getenv("GITHUB_WEBHOOK_SECRET")),
    Header:   "X-Hub-Signature-256",
    Prefix:   "sha256=",
    Algorithm: "sha256",
}))
```

### Stripe Webhook

```go theme={null}
app.Post("/webhook/stripe", handler, signature.New(signature.Options{
    Secret:           []byte(os.Getenv("STRIPE_WEBHOOK_SECRET")),
    Header:           "Stripe-Signature",
    TimestampHeader:  "Stripe-Signature",
    ParseStripeStyle: true,
}))
```

### With Timestamp Validation

```go theme={null}
app.Use(signature.New(signature.Options{
    Secret:             []byte("api-secret"),
    Header:             "X-Signature",
    TimestampHeader:    "X-Timestamp",
    TimestampTolerance: 5 * time.Minute,
}))
```

### Per-Client Secrets

```go theme={null}
app.Use(signature.New(signature.Options{
    Header: "X-Signature",
    GetSecret: func(c *mizu.Ctx) []byte {
        clientID := c.Request().Header.Get("X-Client-ID")
        return getClientSecret(clientID)
    },
}))
```

### Custom Signature Format

```go theme={null}
app.Use(signature.New(signature.Options{
    Secret:    secret,
    Header:    "Authorization",
    Prefix:    "HMAC-SHA256 ",
    Algorithm: "sha256",
    Encoding:  "base64",
}))
```

## API Reference

### Functions

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

// Sign generates signature for data
func Sign(data, secret []byte, algorithm string) string

// Verify checks if signature is valid
func Verify(data, secret []byte, signature, algorithm string) bool
```

## Signature Algorithms

| Algorithm | Description               |
| --------- | ------------------------- |
| `sha256`  | HMAC-SHA256 (recommended) |
| `sha512`  | HMAC-SHA512               |
| `sha1`    | HMAC-SHA1 (legacy)        |

## Creating Signatures (Client Side)

```go theme={null}
// Go client
func signRequest(body []byte, secret string) string {
    mac := hmac.New(sha256.New, []byte(secret))
    mac.Write(body)
    return hex.EncodeToString(mac.Sum(nil))
}
```

```javascript theme={null}
// JavaScript client
async function signRequest(body, secret) {
    const encoder = new TextEncoder();
    const key = await crypto.subtle.importKey(
        'raw', encoder.encode(secret),
        { name: 'HMAC', hash: 'SHA-256' },
        false, ['sign']
    );
    const sig = await crypto.subtle.sign('HMAC', key, encoder.encode(body));
    return Array.from(new Uint8Array(sig))
        .map(b => b.toString(16).padStart(2, '0'))
        .join('');
}
```

## Technical Details

### Implementation Architecture

The signature middleware implements HMAC-based request verification using Go's crypto packages:

* **Algorithm Support**: SHA-1 (legacy), SHA-256 (default), SHA-512
* **Encoding Formats**: Hexadecimal (default) and Base64
* **Signature Verification**: Constant-time comparison using `hmac.Equal()` to prevent timing attacks

### Core Components

#### Middleware Flow

1. **Path & Method Filtering**: Checks if request should skip validation based on configured paths and methods
2. **Signature Extraction**: Retrieves signature from configured header and validates prefix if specified
3. **Payload Reading**: Uses default body reader or custom `PayloadGetter` function
4. **HMAC Verification**: Computes expected signature and performs constant-time comparison
5. **Context Storage**: Stores verification result in request context for downstream handlers

#### Key Functions

* `New(secret)`: Creates middleware with default options (SHA-256, hex encoding, X-Signature header)
* `WithOptions(opts)`: Creates middleware with custom configuration
* `Sign(secret, algo, encoding, payload)`: Generates HMAC signature for given payload
* `GetInfo(c)`: Retrieves signature verification information from context
* `IsValid(c)`: Quick check if signature was valid

#### Provider-Specific Helpers

The middleware includes pre-configured functions for popular webhook providers:

* **GitHub**: `X-Hub-Signature-256` header with `sha256=` prefix
* **Stripe**: `Stripe-Signature` header (simplified implementation)
* **Slack**: Custom payload format combining version, timestamp, and body
* **Twilio**: SHA-1 with Base64 encoding, URL + sorted form parameters
* **AWS**: Signature Version 4 (simplified implementation)

### Security Features

* **Constant-Time Comparison**: Uses `hmac.Equal()` to prevent timing attacks
* **Body Preservation**: Re-wraps request body after reading for downstream handlers
* **Configurable Skip Rules**: Allows excluding specific paths and HTTP methods
* **Custom Error Handling**: Supports custom error responses via `ErrorHandler`

## Best Practices

* Use SHA-256 or stronger algorithms
* Include timestamp to prevent replay attacks
* Use secure random secrets (32+ bytes)
* Rotate secrets periodically
* Log signature failures for security monitoring

## Testing

The signature middleware includes comprehensive test coverage for all features and edge cases:

| Test Case                       | Description                                    | Expected Behavior                                |
| ------------------------------- | ---------------------------------------------- | ------------------------------------------------ |
| `TestNew`                       | Basic middleware creation with default options | GET requests skip validation (default behavior)  |
| `TestValidSignature`            | Valid HMAC-SHA256 signature verification       | Request accepted with 200 OK                     |
| `TestInvalidSignature`          | Invalid signature provided                     | Request rejected with 401 Unauthorized           |
| `TestMissingSignature`          | No signature header present                    | Request rejected with 401 Unauthorized           |
| `TestSignaturePrefix`           | Signature with prefix (e.g., "sha256=")        | Prefix validated and stripped correctly          |
| `TestBase64Encoding`            | Base64-encoded signature verification          | Signature decoded and verified                   |
| `TestSHA1Algorithm`             | SHA-1 algorithm (legacy support)               | Signature verified with SHA-1 HMAC               |
| `TestSHA512Algorithm`           | SHA-512 algorithm verification                 | Signature verified with SHA-512 HMAC             |
| `TestSkipPaths`                 | Configured paths excluded from validation      | Skipped paths accept requests without signatures |
| `TestCustomHeaderName`          | Custom signature header name                   | Signature read from custom header                |
| `TestCustomErrorHandler`        | Custom error response handler                  | Custom error format returned on failure          |
| `TestOnValid`                   | Callback function on successful validation     | OnValid callback executed                        |
| `TestGetInfo`                   | Retrieve signature info from context           | Info object contains validation details          |
| `TestIsValid`                   | Check if signature is valid                    | Returns true for valid signatures                |
| `TestGitHub`                    | GitHub webhook signature format                | X-Hub-Signature-256 with sha256= prefix verified |
| `TestSign`                      | Signature generation for various algorithms    | Consistent signatures generated for same input   |
| `TestSigner`                    | Client-side request signing                    | Signature header added to outgoing requests      |
| `TestSignerWithPrefix`          | Signer with prefix configuration               | Signature includes configured prefix             |
| `TestSignerNilBody`             | Signing request with nil body                  | Handles nil body gracefully                      |
| `TestStripe`                    | Stripe webhook signature verification          | Stripe-Signature header verified                 |
| `TestSlack`                     | Slack signature with timestamp format          | v0=HMAC(v0:timestamp:body) format verified       |
| `TestTwilio`                    | Twilio signature with form parameters          | SHA-1 Base64 signature of URL + sorted params    |
| `TestAWS`                       | AWS Signature Version 4 (simplified)           | Authorization header signature verified          |
| `TestGetInfo_NoContext`         | GetInfo without signature middleware           | Returns nil when middleware not used             |
| `TestIsValid_NoContext`         | IsValid without signature middleware           | Returns false when middleware not used           |
| `TestSignaturePrefix_Missing`   | Required prefix not present                    | Request rejected with 401 Unauthorized           |
| `TestCustomPayloadGetter`       | Custom payload extraction function             | Uses custom payload for verification             |
| `TestCustomPayloadGetter_Error` | PayloadGetter returns error                    | Request rejected with 401 Unauthorized           |
| `TestSignUnknownAlgorithm`      | Unknown algorithm specified                    | Defaults to SHA-256                              |
| `TestSkipMethods_Custom`        | Custom skip methods configuration              | Configured methods skip validation               |
| `TestSignerSign_Direct`         | Direct Sign method on Signer                   | Signature added with all custom options          |

## Related Middlewares

* [keyauth](/middlewares/keyauth) - API key authentication
* [jwt](/middlewares/jwt) - JWT authentication
* [hmac](/middlewares/hmac) - HMAC utilities
