π¬ Extractors
The extractors package provides shared value extraction utilities for Fiber middleware packages. It helps reduce code duplication across middleware packages while ensuring consistent behavior and security practices.
Overviewβ
The github.com/gofiber/fiber/v3/extractors
module provides standardized value extraction utilities integrated into Fiber's middleware ecosystem. This approach:
- Reduces Code Duplication: Eliminates redundant extractor implementations across middleware packages
- Ensures Consistency: Maintains identical behavior and security practices across all extractors
- Simplifies Maintenance: Changes to extraction logic only need to be made in one place
- Enables Direct Usage: Middleware can import and use extractors directly
- Improves Performance: Shared, optimized extraction functions reduce overhead
What Are Extractors?β
Extractors are utilities that middleware uses to get values from different parts of HTTP requests:
Available Extractorsβ
FromAuthHeader(authScheme string)
: Extract from Authorization header with optional schemeFromCookie(key string)
: Extract from HTTP cookiesFromParam(param string)
: Extract from URL path parametersFromForm(param string)
: Extract from form dataFromHeader(header string)
: Extract from custom HTTP headersFromQuery(param string)
: Extract from URL query parametersFromCustom(key string, fn func(fiber.Ctx) (string, error))
: Define custom extraction logic with metadataChain(extractors ...Extractor)
: Chain multiple extractors with fallback logic
Extractor Structureβ
Each Extractor
contains:
type Extractor struct {
Extract func(fiber.Ctx) (string, error) // Extraction function
Key string // Parameter/header name
Source Source // Source type for inspection
AuthScheme string // Auth scheme (FromAuthHeader)
Chain []Extractor // Chained extractors
}
- Headers:
Authorization
,X-API-Key
, custom headers - Cookies: Session cookies, authentication tokens
- Query Parameters: URL parameters like
?token=abc123
- Form Data: POST body form fields
- URL Parameters: Route parameters like
/users/:id
Chain Behaviorβ
The Chain
function creates extractors that try multiple sources in order:
- Returns the first successful extraction (non-empty value with no error)
- If all extractors fail, returns the last error encountered or
ErrNotFound
- Robust error handling: Skips extractors with
nil
Extract functions - Preserves the source and key from the first extractor for metadata
- Stores a defensive copy of all chained extractors for introspection via the
Chain
field
Why Middleware Uses Extractorsβ
Middleware needs to extract values from requests for authentication, authorization, and other purposes. Extractors provide:
- Security Awareness: Different sources have different security implications
- Fallback Support: Try multiple sources if the first one doesn't have the value
- Consistency: Same extraction logic across all middleware packages
- Source Tracking: Know where values came from for security decisions
Usage Examplesβ
Basic Usageβ
// KeyAuth middleware extracts key from header
app.Use(keyauth.New(keyauth.Config{
Extractor: extractors.FromHeader("Middleware-Key"),
}))
Fallback Chainsβ
// Try multiple sources in order
tokenExtractor := extractors.Chain(
extractors.FromHeader("Middleware-Key"), // Try header first
extractors.FromCookie("middleware_key"), // Then cookie
extractors.FromQuery("middleware_key"), // Finally query param
)
app.Use(keyauth.New(keyauth.Config{
Extractor: tokenExtractor,
}))
Configuring Middleware That Uses Extractorsβ
Authentication Middlewareβ
// KeyAuth middleware (default: FromAuthHeader)
app.Use(keyauth.New(keyauth.Config{
// Default extracts from Authorization header
// Extractor: extractors.FromAuthHeader("Bearer"),
}))
// Custom header extraction
app.Use(keyauth.New(keyauth.Config{
Extractor: extractors.FromHeader("X-API-Key"),
}))
// Multiple sources with secure fallback
app.Use(keyauth.New(keyauth.Config{
Extractor: extractors.Chain(
extractors.FromAuthHeader("Bearer"), // Secure first
extractors.FromHeader("X-API-Key"), // Then custom header
extractors.FromQuery("api_key"), // Least secure last
),
}))
Session Middlewareβ
// Session middleware (default: FromCookie)
app.Use(session.New(session.Config{
// Default extracts from session_id cookie
// Extractor: extractors.FromCookie("session_id"),
}))
// Custom cookie name
app.Use(session.New(session.Config{
Extractor: extractors.FromCookie("my_session"),
}))
CSRF Middlewareβ
// CSRF middleware (default: FromHeader)
app.Use(csrf.New(csrf.Config{
// Default extracts from X-CSRF-Token header
// Extractor: extractors.FromHeader("X-CSRF-Token"),
}))
// Form-based CSRF (less secure, use only if needed)
app.Use(csrf.New(csrf.Config{
Extractor: extractors.Chain(
extractors.FromHeader("X-CSRF-Token"), // Secure first
extractors.FromForm("_csrf"), // Form fallback
),
}))
Security Considerationsβ
Source Characteristicsβ
Different extraction sources have different security properties and use cases:
Headers (Generally Preferred)β
- Authorization Header: Standard for authentication tokens, widely supported
- Custom Headers: Application-specific, less likely to be logged by default
- Considerations: Can be intercepted without HTTPS, may be stripped by proxies
Cookies (Good for Sessions)β
- Session Cookies: Designed for secure client-side storage
- Considerations: Require proper
Secure
,HttpOnly
, andSameSite
flags - Best for: Session management, remember-me tokens
Query Parameters (Use Sparingly)β
- Query parameters: Convenient for simple APIs and debugging
- Considerations: Always visible in URLs, logged by servers/proxies, stored in browser history
- Best for: Non-sensitive parameters, public identifiers
Form Data (Context Dependent)β
- POST Bodies: Suitable for form submissions and API requests
- Considerations: Avoid putting sensitive data in query strings; ensure request bodies arenβt logged and use the correct content type
- Best for: User-generated content, file uploads
Security Best Practicesβ
- Use HTTPS: Encrypt all traffic to protect extracted values in transit
- Validate Input: Always validate and sanitize extracted values
- Log Carefully: Avoid logging sensitive values from any source
- Choose Appropriate Sources: Match the source to your security requirements
- Test Thoroughly: Verify extraction works in your environment
- Monitor Security: Watch for extraction failures or unusual patterns
Chain Ordering Strategyβ
When using multiple sources, order them by your security preferences:
// Example: Prefer headers, fallback to cookies, then query
extractors.Chain(
extractors.FromAuthHeader("Bearer"), // Standard auth
extractors.FromCookie("auth_token"), // Secure storage
extractors.FromQuery("token"), // Public fallback
)
The "best" source depends on your specific use case, security requirements, and application architecture.
Common Security Issuesβ
Leaky URLsβ
// β DON'T: API keys in URLs (visible in logs, history, bookmarks)
app.Use(keyauth.New(keyauth.Config{
Extractor: extractors.FromQuery("api_key"), // PROBLEMATIC
}))
// β
DO: API keys in headers (not visible in URLs)
app.Use(keyauth.New(keyauth.Config{
Extractor: extractors.FromHeader("X-API-Key"), // BETTER
}))
Session Tokens in Query Parametersβ
// β DON'T: Session tokens in URLs (can be bookmarked, leaked)
app.Use(session.New(session.Config{
Extractor: extractors.FromQuery("session"), // PROBLEMATIC
}))
// β
DO: Session tokens in cookies (designed for this purpose)
app.Use(session.New(session.Config{
Extractor: extractors.FromCookie("session_id"), // BETTER
}))
Form-Only CSRF Tokensβ
While the default extractor uses headers, some implementations use form fields, which is fine if you don't have AJAX or API clients:
// β DON'T: CSRF tokens only in forms (breaks AJAX, API calls)
app.Use(csrf.New(csrf.Config{
Extractor: extractors.FromForm("_csrf"), // LIMITED
}))
// β
DO: Header-first with form fallback (works everywhere)
app.Use(csrf.New(csrf.Config{
Extractor: extractors.Chain(
extractors.FromHeader("X-CSRF-Token"), // PREFERRED
extractors.FromForm("_csrf"), // FALLBACK
),
}))
Understanding Trade-offsβ
No extractor is universally "secure" - security depends on:
- Whether you're using HTTPS
- How you configure cookies (Secure, HttpOnly, SameSite flags)
- Your logging and monitoring setup
- The sensitivity of the data being extracted
- Your threat model and security requirements
Choose extractors based on your specific use case and security needs, not blanket "secure" vs "insecure" labels.
Standards Complianceβ
Authorization Header (RFC 9110 & RFC 7235)β
The FromAuthHeader
extractor provides comprehensive RFC compliance with strict security validation:
RFC 9110 Compliance (Authorization Header Format)β
- Section 11.6.2 Format: Enforces
credentials = auth-scheme 1*SP token68
structure - 1*SP Requirement: Validates exactly one or more spaces between auth-scheme and token
- Case-insensitive scheme matching:
Bearer
,bearer
,BEARER
all work correctly - Proper whitespace handling: Rejects tabs between scheme and token (only spaces allowed)
RFC 7235 Token68 Validationβ
The extractor implements strict token68 character validation per RFC 7235:
- Allowed characters:
A-Z
,a-z
,0-9
,-
,.
,_
,~
,+
,/
,=
- Padding rules:
=
characters only allowed at the end of tokens - Security validation: Prevents tokens starting with
=
or having non-padding characters after=
- Whitespace rejection: Rejects tokens containing spaces, tabs, or any other whitespace
Security Featuresβ
- Header injection prevention: Strict parsing prevents malformed authorization headers from bypassing authentication
- Token validation: Ensures extracted tokens conform to standards, preventing authentication bypass
- Consistent error handling: Returns
ErrNotFound
for all invalid cases
Examplesβ
// Standard usage - strict validation
extractor := extractors.FromAuthHeader("Bearer")
// β
Valid cases:
// "Bearer abc123" -> "abc123"
// "bearer ABC123" -> "ABC123" (case-insensitive scheme)
// "Bearer token123=" -> "token123=" (valid padding)
// "Bearer token==" -> "token==" (valid multiple padding)
// β Invalid cases (all return ErrNotFound):
// "Bearer abc def" -> rejected (space in token)
// "Bearer abc\tdef" -> rejected (tab in token)
// "Bearer =abc" -> rejected (padding at start)
// "Bearer ab=cd" -> rejected (padding in middle)
// "Bearer token" -> rejected (multiple spaces after scheme)
// "Bearer\ttoken" -> rejected (tab after scheme)
// "Bearertoken" -> rejected (no space after scheme)
// Raw header extraction (no validation)
rawExtractor := extractors.FromAuthHeader("")
// "CustomAuth anything goes here" -> "CustomAuth anything goes here"
Benefitsβ
- Standards Compliance: Full adherence to HTTP authentication RFCs
- Security Hardening: Prevents common authentication bypass vulnerabilities
- Consistent Behavior: Reliable parsing across different client implementations
- Developer Confidence: Clear validation rules reduce authentication bugs
Troubleshootingβ
Extraction Failsβ
Problem: Middleware returns "value not found" or authentication fails
Solutions:
- Check if the expected header/cookie/query parameter is present
- Verify the key name matches exactly (headers are case-insensitive; params/cookies/query keys are case-sensitive)
- Ensure the request uses the correct HTTP method (GET vs POST)
- Check if middleware is configured with the right extractor
Debug Example:
// Add simple debug logging (avoid logging secrets in production)
app.Use(func(c fiber.Ctx) error {
hdr := c.Get("X-API-Key")
cookie := c.Cookies("session_id")
if hdr != "" || cookie != "" {
log.Printf("debug: X-API-Key present=%t, session_id present=%t", hdr != "", cookie != "")
}
return c.Next()
})
Wrong Source Usedβ
Problem: Values extracted from unexpected sources
Solutions:
- Check middleware configuration order
- Verify chain order (first successful extraction wins)
- Use more specific extractors when needed
Security Warningsβ
Problem: Getting security warnings in logs
Solutions:
- Switch to more secure sources (headers/cookies)
- Use HTTPS to encrypt traffic
- Review if sensitive data should be in that source
Advanced Usageβ
Custom Extraction Logicβ
Extractors support custom extractors for complex scenarios:
// Extract from custom logic (rarely needed)
customExtractor := extractors.FromCustom("my-source", func(c fiber.Ctx) (string, error) {
// Complex extraction logic
if value := c.Locals("computed_token"); value != nil {
return value.(string), nil
}
return "", extractors.ErrNotFound
})
Custom extractors break source awareness. When you use FromCustom
, middleware cannot determine where the value came from, which means:
- No automatic security warnings for potentially insecure sources
- No source-based logging or monitoring capabilities
- Developer responsibility for ensuring the extraction is secure and appropriate
Only use FromCustom
when:
- Standard extractors don't meet your needs
- You've carefully evaluated the security implications
- You're confident in the security of your custom extraction logic
- You understand that middleware cannot provide source-aware security guidance
Note: If you pass nil
as the function parameter, FromCustom
will return an extractor that always fails with ErrNotFound
.
Multiple Middleware Coordinationβ
When using multiple middleware that extract values, ensure they don't conflict:
// Good: Different sources for different purposes
app.Use(keyauth.New(keyauth.Config{
Extractor: extractors.FromHeader("X-API-Key"),
}))
app.Use(session.New(session.Config{
Extractor: extractors.FromCookie("session_id"),
}))
// Avoid: Same source for different middleware
app.Use(keyauth.New(keyauth.Config{
Extractor: extractors.FromCookie("token"), // API auth
}))
app.Use(session.New(session.Config{
Extractor: extractors.FromCookie("token"), // Session - CONFLICT!
}))