Skip to main content
The Early Data middleware adds TLS 1.3 “0-RTT” support to Fiber. When the client and server share a PSK, TLS 1.3 lets the client send data with the first flight and skip the initial round trip.
Enable Fiber’s TrustProxy option before using this middleware to avoid spoofed client headers. When TrustProxy is disabled (the default) or the remote address is not trusted by your proxy configuration, requests carrying the Early-Data header are rejected with 425 Too Early to prevent 0-RTT spoofing from direct clients.
Enabling early data in a reverse proxy (for example, ssl_early_data on; in nginx) makes requests replayable. Review the security implications:
By default, the middleware permits early data only for safe methods (GET, HEAD, OPTIONS, TRACE) and rejects other requests before your handler runs. Override this behavior with the AllowEarlyData option.

Signatures

func New(config ...Config) fiber.Handler
func IsEarly(c fiber.Ctx) bool
IsEarly returns true when a request used early data and the middleware allowed it to proceed.

Usage

import (
    "github.com/gofiber/fiber/v3"
    "github.com/gofiber/fiber/v3/middleware/earlydata"
)

Basic Example

// Initialize default config
app.Use(earlydata.New())

// Or extend your config for customization
app.Use(earlydata.New(earlydata.Config{
    Error: fiber.ErrTooEarly,
}))

Check if Request Used Early Data

app.Get("/", func(c fiber.Ctx) error {
    if earlydata.IsEarly(c) {
        // Request came via 0-RTT
        return c.SendString("Early data was used!")
    }
    return c.SendString("Normal request")
})

Configuration

Next
func(fiber.Ctx) bool
default:"nil"
Skip this middleware when the function returns true.
IsEarlyData
func(fiber.Ctx) bool
Reports whether the request used early data.
AllowEarlyData
func(fiber.Ctx) bool
Decides if an early-data request should be allowed.
Error
error
default:"fiber.ErrTooEarly"
Returned when an early-data request is rejected.

Default Config

var ConfigDefault = Config{
    IsEarlyData: func(c fiber.Ctx) bool {
        return c.Get(DefaultHeaderName) == DefaultHeaderTrueValue
    },
    AllowEarlyData: func(c fiber.Ctx) bool {
        return fiber.IsMethodSafe(c.Method())
    },
    Error: fiber.ErrTooEarly,
}

Constants

const (
    DefaultHeaderName      = "Early-Data"
    DefaultHeaderTrueValue = "1"
)

Common Use Cases

Allow Early Data for Specific Routes

app.Use(earlydata.New(earlydata.Config{
    AllowEarlyData: func(c fiber.Ctx) bool {
        // Only allow early data for read-only API endpoints
        return strings.HasPrefix(c.Path(), "/api/read/") && 
               fiber.IsMethodSafe(c.Method())
    },
}))

Custom Early Data Detection

app.Use(earlydata.New(earlydata.Config{
    IsEarlyData: func(c fiber.Ctx) bool {
        // Check custom header from your proxy
        return c.Get("X-Early-Data") == "true"
    },
}))

Strict Security - Reject All Early Data

app.Use(earlydata.New(earlydata.Config{
    AllowEarlyData: func(c fiber.Ctx) bool {
        return false // Reject all early data requests
    },
}))

Logging Early Data Requests

app.Use(earlydata.New())

app.Use(func(c fiber.Ctx) error {
    if earlydata.IsEarly(c) {
        log.Printf("Early data request: %s %s", c.Method(), c.Path())
    }
    return c.Next()
})

Build docs developers (and LLMs) love