Documentation
¶
Overview ¶
Package jwtmiddleware provides HTTP middleware for JWT authentication.
This package implements JWT authentication middleware for standard Go net/http servers. It validates JWTs, extracts claims, and makes them available in the request context. The middleware follows the Core-Adapter pattern, with this package serving as the HTTP transport adapter.
Quick Start ¶
import (
"github.com/auth0/go-jwt-middleware/v3"
"github.com/auth0/go-jwt-middleware/v3/jwks"
"github.com/auth0/go-jwt-middleware/v3/validator"
)
func main() {
// Create JWKS provider
issuerURL, _ := url.Parse("https://your-domain.auth0.com/")
provider, err := jwks.NewCachingProvider(
jwks.WithIssuerURL(issuerURL),
)
if err != nil {
log.Fatal(err)
}
// Create validator
jwtValidator, err := validator.New(
validator.WithKeyFunc(provider.KeyFunc),
validator.WithAlgorithm(validator.RS256),
validator.WithIssuer(issuerURL.String()),
validator.WithAudience("your-api-identifier"),
)
if err != nil {
log.Fatal(err)
}
// Create middleware
middleware, err := jwtmiddleware.New(
jwtmiddleware.WithValidator(jwtValidator),
)
if err != nil {
log.Fatal(err)
} // Use with your HTTP server
http.Handle("/api/", middleware.CheckJWT(apiHandler))
http.ListenAndServe(":8080", nil)
}
Accessing Claims ¶
Use the type-safe generic helpers to access claims in your handlers:
func apiHandler(w http.ResponseWriter, r *http.Request) {
// Type-safe claims retrieval
claims, err := jwtmiddleware.GetClaims[*validator.ValidatedClaims](r.Context())
if err != nil {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
// Access claims
fmt.Fprintf(w, "Hello, %s!", claims.RegisteredClaims.Subject)
}
Alternative: Check if claims exist without retrieving them:
if jwtmiddleware.HasClaims(r.Context()) {
// Claims are present
}
v2 compatibility (type assertion):
claimsValue := r.Context().Value(jwtmiddleware.ContextKey{})
if claimsValue == nil {
// No claims
}
claims := claimsValue.(*validator.ValidatedClaims)
Configuration Options ¶
All configuration is done through functional options:
Required:
- WithValidator: A configured validator instance
Optional:
- WithCredentialsOptional: Allow requests without JWT
- WithValidateOnOptions: Validate JWT on OPTIONS requests
- WithErrorHandler: Custom error response handler
- WithTokenExtractor: Custom token extraction logic
- WithExclusionUrls: URLs to skip JWT validation
- WithLogger: Structured logging (compatible with log/slog)
Optional Credentials ¶
Allow requests without JWT (useful for public + authenticated endpoints):
middleware, err := jwtmiddleware.New(
jwtmiddleware.WithValidator(jwtValidator),
jwtmiddleware.WithCredentialsOptional(true),
) func handler(w http.ResponseWriter, r *http.Request) {
claims, err := jwtmiddleware.GetClaims[*validator.ValidatedClaims](r.Context())
if err != nil {
// No JWT provided - serve public content
fmt.Fprintln(w, "Public content")
return
}
// JWT provided - serve authenticated content
fmt.Fprintf(w, "Hello, %s!", claims.RegisteredClaims.Subject)
}
Custom Error Handling ¶
Implement custom error responses:
func myErrorHandler(w http.ResponseWriter, r *http.Request, err error) {
log.Printf("JWT error: %v", err)
// Check error type
if errors.Is(err, jwtmiddleware.ErrJWTMissing) {
http.Error(w, "No token provided", http.StatusUnauthorized)
return
}
// Check for ValidationError
var validationErr *core.ValidationError
if errors.As(err, &validationErr) {
switch validationErr.Code {
case core.ErrorCodeTokenExpired:
http.Error(w, "Token expired", http.StatusUnauthorized)
default:
http.Error(w, "Invalid token", http.StatusUnauthorized)
}
return
}
http.Error(w, "Unauthorized", http.StatusUnauthorized)
}
middleware, err := jwtmiddleware.New(
jwtmiddleware.WithValidator(jwtValidator),
jwtmiddleware.WithErrorHandler(myErrorHandler),
)# Token Extraction
Default: Authorization header with Bearer scheme
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
Custom extractors:
From Cookie:
extractor := jwtmiddleware.CookieTokenExtractor("jwt")
From Query Parameter:
extractor := jwtmiddleware.ParameterTokenExtractor("token")
Multiple Sources (tries in order):
extractor := jwtmiddleware.MultiTokenExtractor(
jwtmiddleware.AuthHeaderTokenExtractor,
jwtmiddleware.CookieTokenExtractor("jwt"),
)
Use with middleware:
middleware, err := jwtmiddleware.New( jwtmiddleware.WithValidator(jwtValidator), jwtmiddleware.WithTokenExtractor(extractor), )# URL Exclusions
Skip JWT validation for specific URLs:
middleware, err := jwtmiddleware.New(
jwtmiddleware.WithValidator(jwtValidator),
jwtmiddleware.WithExclusionUrls([]string{
"/health",
"/metrics",
"/public",
}),
)# Logging
Enable structured logging (compatible with log/slog):
import "log/slog" logger := slog.New(slog.NewJSONHandler(os.Stdout, nil)) middleware, err := jwtmiddleware.New( jwtmiddleware.WithValidator(jwtValidator), jwtmiddleware.WithLogger(logger), )Logs will include: - Token extraction attempts - Validation success/failure with timing - Excluded URLs - OPTIONS request handling
Error Responses ¶
The DefaultErrorHandler provides RFC 6750 compliant error responses:
401 Unauthorized (missing token):
{
"error": "invalid_request",
"error_description": "Authorization header required"
}
WWW-Authenticate: Bearer realm="api"
401 Unauthorized (invalid token):
{
"error": "invalid_token",
"error_description": "Token has expired",
"error_code": "token_expired"
}
WWW-Authenticate: Bearer error="invalid_token", error_description="Token has expired"
400 Bad Request (extraction error):
{
"error": "invalid_request",
"error_description": "Authorization header format must be Bearer {token}"
}
Context Key ¶
v3 uses an unexported context key for collision-free claims storage:
type contextKey int
This prevents conflicts with other packages. Always use the provided helper functions (GetClaims, HasClaims, SetClaims) to access claims.
v2 compatibility: The exported ContextKey{} struct is still available:
claimsValue := r.Context().Value(jwtmiddleware.ContextKey{})
However, the generic helpers are recommended for type safety.
Custom Claims ¶
Define and use custom claims in your handlers:
type MyCustomClaims struct {
Scope string `json:"scope"`
Permissions []string `json:"permissions"`
}
func (c *MyCustomClaims) Validate(ctx context.Context) error {
if c.Scope == "" {
return errors.New("scope is required")
}
return nil
}
Configure validator with custom claims:
jwtValidator, err := validator.New(
validator.WithKeyFunc(provider.KeyFunc),
validator.WithAlgorithm(validator.RS256),
validator.WithIssuer(issuerURL.String()),
validator.WithAudience("your-api-identifier"),
validator.WithCustomClaims(func() *MyCustomClaims {
return &MyCustomClaims{}
}),
)
Access in handlers:
func handler(w http.ResponseWriter, r *http.Request) {
claims, _ := jwtmiddleware.GetClaims[*validator.ValidatedClaims](r.Context())
customClaims := claims.CustomClaims.(*MyCustomClaims)
if contains(customClaims.Permissions, "read:data") {
// User has permission
}
}
Thread Safety ¶
The JWTMiddleware instance is immutable after creation and safe for concurrent use. The same middleware can be used across multiple routes and handle concurrent requests.
Performance ¶
Typical request overhead with JWKS caching:
- Token extraction: <0.1ms
- Signature verification: <1ms (cached keys)
- Claims validation: <0.1ms
- Total: <2ms per request
First request (cold cache):
- OIDC discovery: ~100-300ms
- JWKS fetch: ~50-200ms
- Validation: <1ms
- Total: ~150-500ms
Architecture ¶
This package is the HTTP adapter in the Core-Adapter pattern:
┌─────────────────────────────────────────────┐
│ HTTP Middleware (THIS PACKAGE) │
│ - Token extraction from HTTP requests │
│ - Error responses (401, 400) │
│ - Context integration │
└────────────────┬────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ Core Engine │
│ (Framework-Agnostic Validation Logic) │
└────────────────┬────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ Validator │
│ (JWT Parsing & Verification) │
└─────────────────────────────────────────────┘
This design allows the same validation logic to be used with different transports (HTTP, gRPC, WebSocket, etc.) without code duplication.
Migration from v2 ¶
Key changes from v2 to v3:
1. Options Pattern: All configuration via functional options
// v2
jwtmiddleware.New(validator.New, options...)
// v3
jwtmiddleware.New(
jwtmiddleware.WithValidator(validator),
jwtmiddleware.WithCredentialsOptional(false),
)2. Generic Claims Retrieval: Type-safe with generics
// v2
claims := r.Context().Value(jwtmiddleware.ContextKey{}).(*validator.ValidatedClaims)
// v3
claims, err := jwtmiddleware.GetClaims[*validator.ValidatedClaims](r.Context())
3. Validator Options: Pure options pattern
// v2
validator.New(keyFunc, alg, issuer, audience, opts...)
// v3
validator.New(
validator.WithKeyFunc(keyFunc),
validator.WithAlgorithm(validator.RS256),
validator.WithIssuer(issuer),
validator.WithAudience(audience),
)
4. JWKS Provider: Pure options pattern
// v2
jwks.NewProvider(issuerURL, options...)
// v3
jwks.NewCachingProvider(
jwks.WithIssuerURL(issuerURL),
jwks.WithCacheTTL(15*time.Minute),
)
5. ExclusionUrlHandler → ExclusionURLHandler: Proper URL capitalization
See MIGRATION.md for a complete guide.
Index ¶
- Constants
- Variables
- func DPoPHeaderExtractor(r *http.Request) (string, error)
- func DefaultErrorHandler(w http.ResponseWriter, r *http.Request, err error)
- func GetClaims[T any](ctx context.Context) (T, error)
- func GetDPoPContext(ctx context.Context) *core.DPoPContext
- func HasClaims(ctx context.Context) bool
- func HasDPoPContext(ctx context.Context) bool
- func MustGetClaims[T any](ctx context.Context) T
- type AuthScheme
- type DPoPMode
- type ErrorHandler
- type ErrorResponse
- type ExclusionURLHandler
- type ExtractedToken
- type JWTMiddleware
- type Logger
- type Option
- func WithAPIGatewayProxy() Option
- func WithCredentialsOptional(value bool) Option
- func WithDPoPHeaderExtractor(extractor func(*http.Request) (string, error)) Option
- func WithDPoPIATLeeway(leeway time.Duration) Option
- func WithDPoPMode(mode core.DPoPMode) Option
- func WithDPoPProofOffset(offset time.Duration) Option
- func WithErrorHandler(h ErrorHandler) Option
- func WithExclusionUrls(exclusions []string) Option
- func WithLogger(logger Logger) Option
- func WithRFC7239Proxy() Option
- func WithStandardProxy() Option
- func WithTokenExtractor(e TokenExtractor) Option
- func WithTrustedProxies(config *TrustedProxyConfig) Option
- func WithValidateOnOptions(value bool) Option
- func WithValidator(v *validator.Validator) Option
- type TokenExtractor
- type TrustedProxyConfig
Constants ¶
const ( // AuthSchemeBearer represents Bearer token authorization. AuthSchemeBearer = core.AuthSchemeBearer // AuthSchemeDPoP represents DPoP token authorization. AuthSchemeDPoP = core.AuthSchemeDPoP // AuthSchemeUnknown represents an unknown or missing authorization scheme. AuthSchemeUnknown = core.AuthSchemeUnknown )
Variables ¶
var ( // ErrJWTMissing is returned when the JWT is missing. // This is the same as core.ErrJWTMissing for consistency. ErrJWTMissing = core.ErrJWTMissing // ErrJWTInvalid is returned when the JWT is invalid. // This is the same as core.ErrJWTInvalid for consistency. ErrJWTInvalid = core.ErrJWTInvalid )
var ( ErrValidatorNil = errors.New("validator cannot be nil (use WithValidator)") ErrErrorHandlerNil = errors.New("errorHandler cannot be nil") ErrTokenExtractorNil = errors.New("tokenExtractor cannot be nil") ErrExclusionUrlsEmpty = errors.New("exclusion URLs list cannot be empty") ErrLoggerNil = errors.New("logger cannot be nil") ErrDPoPHeaderExtractorNil = errors.New("DPoP header extractor cannot be nil") )
Sentinel errors for configuration validation
Functions ¶
func DPoPHeaderExtractor ¶
DPoPHeaderExtractor extracts the DPoP proof from the "DPoP" HTTP header. Returns empty string if the header is not present (which is valid for Bearer tokens). Returns an error if multiple DPoP headers are present (per RFC 9449).
func DefaultErrorHandler ¶
func DefaultErrorHandler(w http.ResponseWriter, r *http.Request, err error)
DefaultErrorHandler is the default error handler implementation. It provides structured error responses with appropriate HTTP status codes and RFC 6750/RFC 9449 compliant WWW-Authenticate headers.
In DPoP allowed mode, both Bearer and DPoP challenges are returned per RFC 9449 Section 6.1.
func GetClaims ¶
GetClaims retrieves claims from the context with type safety using generics. This provides compile-time type checking and eliminates the need for manual type assertions.
Example:
claims, err := jwtmiddleware.GetClaims[*validator.ValidatedClaims](r.Context())
if err != nil {
http.Error(w, "failed to get claims", http.StatusInternalServerError)
return
}
fmt.Println(claims.RegisteredClaims.Subject)
func GetDPoPContext ¶
func GetDPoPContext(ctx context.Context) *core.DPoPContext
GetDPoPContext retrieves the DPoP context from the request context. Returns nil if no DPoP context exists (e.g., for Bearer tokens).
This is a convenience wrapper around core.GetDPoPContext for use in HTTP handlers.
Example:
dpopCtx := jwtmiddleware.GetDPoPContext(r.Context())
if dpopCtx != nil {
log.Printf("DPoP token from key: %s", dpopCtx.PublicKeyThumbprint)
}
func HasClaims ¶
HasClaims checks if claims exist in the context.
Example:
if jwtmiddleware.HasClaims(r.Context()) {
claims, _ := jwtmiddleware.GetClaims[*validator.ValidatedClaims](r.Context())
// Use claims...
}
func HasDPoPContext ¶
HasDPoPContext checks if a DPoP context exists in the request context. Returns true for DPoP-bound tokens, false for Bearer tokens.
This is a convenience wrapper around core.HasDPoPContext for use in HTTP handlers.
Example:
if jwtmiddleware.HasDPoPContext(r.Context()) {
dpopCtx := jwtmiddleware.GetDPoPContext(r.Context())
// Handle DPoP-specific logic...
}
func MustGetClaims ¶
MustGetClaims retrieves claims from the context or panics. Use only when you are certain claims exist (e.g., after middleware has run).
Example:
claims := jwtmiddleware.MustGetClaims[*validator.ValidatedClaims](r.Context()) fmt.Println(claims.RegisteredClaims.Subject)
Types ¶
type AuthScheme ¶
type AuthScheme = core.AuthScheme
AuthScheme is an alias for core.AuthScheme for backward compatibility. New code should use core.AuthScheme directly.
type DPoPMode ¶
DPoPMode represents the operational mode for DPoP token validation.
const ( // DPoPAllowed accepts both Bearer and DPoP tokens (default, non-breaking). // This mode allows gradual migration from Bearer to DPoP tokens. DPoPAllowed DPoPMode = core.DPoPAllowed // DPoPRequired only accepts DPoP tokens and rejects Bearer tokens. // Use this mode when all clients have been upgraded to support DPoP. DPoPRequired DPoPMode = core.DPoPRequired // DPoPDisabled only accepts Bearer tokens and ignores DPoP headers. // Use this mode to explicitly opt-out of DPoP support. DPoPDisabled DPoPMode = core.DPoPDisabled )
type ErrorHandler ¶
type ErrorHandler func(w http.ResponseWriter, r *http.Request, err error)
ErrorHandler is a handler which is called when an error occurs in the JWTMiddleware. The handler determines the HTTP response when a token is not found, is invalid, or other errors occur.
The default handler (DefaultErrorHandler) provides:
- Structured JSON error responses with error codes
- RFC 6750 compliant WWW-Authenticate headers (Bearer tokens)
- Appropriate HTTP status codes based on error type
- Security-conscious error messages (no sensitive details by default)
- Extensible architecture for future authentication schemes (e.g., DPoP per RFC 9449)
Custom error handlers should check for ErrJWTMissing and ErrJWTInvalid sentinel errors, as well as core.ValidationError for detailed error codes.
Future extensions (e.g., DPoP support) can use the same pattern:
- Add DPoP-specific error codes to core.ValidationError
- Update mapValidationError to handle DPoP errors
- Return appropriate WWW-Authenticate headers with DPoP scheme
type ErrorResponse ¶
type ErrorResponse struct {
// Error is the main error message
Error string `json:"error"`
// ErrorDescription provides additional context (optional)
ErrorDescription string `json:"error_description,omitempty"`
// ErrorCode is a machine-readable error code (optional)
ErrorCode string `json:"error_code,omitempty"`
}
ErrorResponse represents a structured error response.
type ExclusionURLHandler ¶
ExclusionURLHandler is a function that takes in a http.Request and returns true if the request should be excluded from JWT validation.
type ExtractedToken ¶
type ExtractedToken struct {
Token string
Scheme AuthScheme
}
ExtractedToken holds both the extracted token and the authorization scheme used. This allows the middleware to enforce that DPoP scheme requires a DPoP proof.
func AuthHeaderTokenExtractor ¶
func AuthHeaderTokenExtractor(r *http.Request) (ExtractedToken, error)
AuthHeaderTokenExtractor is a TokenExtractor that takes a request and extracts the token and scheme from the Authorization header. Supports both "Bearer" and "DPoP" authorization schemes.
Security: Rejects requests with multiple Authorization headers per RFC 9449.
type JWTMiddleware ¶
type JWTMiddleware struct {
// contains filtered or unexported fields
}
JWTMiddleware is a middleware that validates JWTs and makes claims available in the request context. It wraps the core validation engine and provides HTTP-specific functionality like token extraction and error handling.
Claims are stored in the context using core.SetClaims() and can be retrieved using core.GetClaims[T]().
func New ¶
func New(opts ...Option) (*JWTMiddleware, error)
New constructs a new JWTMiddleware instance with the supplied options. All parameters are passed via options (pure options pattern).
Required options:
- WithValidator: A configured validator instance
Example:
v, err := validator.New(
validator.WithKeyFunc(keyFunc),
validator.WithAlgorithm(validator.RS256),
validator.WithIssuer("https://issuer.example.com/"),
validator.WithAudience("my-api"),
)
if err != nil {
log.Fatal(err)
}
middleware, err := jwtmiddleware.New(
jwtmiddleware.WithValidator(v),
jwtmiddleware.WithCredentialsOptional(false),
)
if err != nil {
log.Fatalf("failed to create middleware: %v", err)
}
type Logger ¶
type Logger interface {
Debug(msg string, args ...any)
Info(msg string, args ...any)
Warn(msg string, args ...any)
Error(msg string, args ...any)
}
Logger defines an optional logging interface compatible with log/slog. This is the same interface used by core for consistent logging across the stack.
type Option ¶
type Option func(*JWTMiddleware) error
Option configures the JWTMiddleware. Returns error for validation failures.
func WithAPIGatewayProxy ¶
func WithAPIGatewayProxy() Option
WithAPIGatewayProxy configures trust for API gateways (AWS API Gateway, Kong, Traefik). Trusts X-Forwarded-Proto, X-Forwarded-Host, and X-Forwarded-Prefix headers. Use this when your gateway adds path prefixes (e.g., /api/v1).
This is a convenience function equivalent to:
WithTrustedProxies(&TrustedProxyConfig{
TrustXForwardedProto: true,
TrustXForwardedHost: true,
TrustXForwardedPrefix: true,
})
Example:
middleware, err := jwtmiddleware.New(
jwtmiddleware.WithValidator(validator),
jwtmiddleware.WithAPIGatewayProxy(),
)
func WithCredentialsOptional ¶
WithCredentialsOptional sets whether credentials are optional. If set to true, an empty token will be considered valid.
Default: false (credentials required)
func WithDPoPHeaderExtractor ¶
WithDPoPHeaderExtractor sets a custom DPoP header extractor. Optional - defaults to extracting from the "DPoP" HTTP header per RFC 9449.
Use this for non-standard scenarios:
- Custom header names (e.g., "X-DPoP-Proof")
- Header transformations (e.g., base64 decoding)
- Alternative sources (e.g., query parameters)
- Testing/mocking
Example (custom header name):
middleware, err := jwtmiddleware.New(
jwtmiddleware.WithValidator(validator),
jwtmiddleware.WithDPoPHeaderExtractor(func(r *http.Request) (string, error) {
return r.Header.Get("X-DPoP-Proof"), nil
}),
)
func WithDPoPIATLeeway ¶
WithDPoPIATLeeway sets the clock skew allowance for DPoP proof iat claims. This allows DPoP proofs with iat timestamps slightly in the future due to clock drift.
Default: 5 seconds
Example:
middleware, err := jwtmiddleware.New(
jwtmiddleware.WithValidator(validator),
jwtmiddleware.WithDPoPIATLeeway(30 * time.Second), // More lenient: 30s
)
func WithDPoPMode ¶
WithDPoPMode sets the DPoP operational mode.
Modes:
- core.DPoPAllowed (default): Accept both Bearer and DPoP tokens
- core.DPoPRequired: Only accept DPoP tokens, reject Bearer tokens
- core.DPoPDisabled: Only accept Bearer tokens, ignore DPoP headers
Example:
middleware, err := jwtmiddleware.New(
jwtmiddleware.WithValidator(validator),
jwtmiddleware.WithDPoPMode(core.DPoPRequired), // Require DPoP
)
func WithDPoPProofOffset ¶
WithDPoPProofOffset sets the maximum age for DPoP proofs. This determines how far in the past a DPoP proof's iat timestamp can be.
Default: 300 seconds (5 minutes)
Example:
middleware, err := jwtmiddleware.New(
jwtmiddleware.WithValidator(validator),
jwtmiddleware.WithDPoPProofOffset(60 * time.Second), // Stricter: 60s
)
func WithErrorHandler ¶
func WithErrorHandler(h ErrorHandler) Option
WithErrorHandler sets the handler called when errors occur during JWT validation. See the ErrorHandler type for more information.
Default: DefaultErrorHandler
func WithExclusionUrls ¶
WithExclusionUrls configures URL patterns to exclude from JWT validation. URLs can be full URLs or just paths.
func WithLogger ¶
WithLogger sets an optional logger for the middleware. The logger will be used throughout the validation flow in both middleware and core.
The logger interface is compatible with log/slog.Logger and similar loggers.
Example:
middleware, err := jwtmiddleware.New(
jwtmiddleware.WithValidateToken(validator.ValidateToken),
jwtmiddleware.WithLogger(slog.Default()),
)
func WithRFC7239Proxy ¶
func WithRFC7239Proxy() Option
WithRFC7239Proxy configures trust for RFC 7239 Forwarded header. This is the most secure option if your proxy supports the structured Forwarded header.
This is a convenience function equivalent to:
WithTrustedProxies(&TrustedProxyConfig{
TrustForwarded: true,
})
Example:
middleware, err := jwtmiddleware.New(
jwtmiddleware.WithValidator(validator),
jwtmiddleware.WithRFC7239Proxy(),
)
func WithStandardProxy ¶
func WithStandardProxy() Option
WithStandardProxy configures trust for standard reverse proxies (Nginx, Apache, HAProxy). Trusts X-Forwarded-Proto and X-Forwarded-Host headers. Use this for typical web server deployments behind a reverse proxy.
This is a convenience function equivalent to:
WithTrustedProxies(&TrustedProxyConfig{
TrustXForwardedProto: true,
TrustXForwardedHost: true,
})
Example:
middleware, err := jwtmiddleware.New(
jwtmiddleware.WithValidator(validator),
jwtmiddleware.WithStandardProxy(),
)
func WithTokenExtractor ¶
func WithTokenExtractor(e TokenExtractor) Option
WithTokenExtractor sets the function to extract the JWT from the request.
Default: AuthHeaderTokenExtractor
func WithTrustedProxies ¶
func WithTrustedProxies(config *TrustedProxyConfig) Option
WithTrustedProxies configures trusted proxy headers for URL reconstruction. Required when behind reverse proxies to correctly validate DPoP HTU claim.
SECURITY WARNING: Only use when your application is behind a trusted reverse proxy that strips client-provided forwarded headers. DO NOT use for direct internet-facing deployments.
Example:
middleware, err := jwtmiddleware.New(
jwtmiddleware.WithValidator(validator),
jwtmiddleware.WithTrustedProxies(&jwtmiddleware.TrustedProxyConfig{
TrustXForwardedProto: true,
TrustXForwardedHost: true,
}),
)
func WithValidateOnOptions ¶
WithValidateOnOptions sets whether OPTIONS requests should have their JWT validated.
Default: true (OPTIONS requests are validated)
func WithValidator ¶
WithValidator configures the middleware with a JWT validator. This is the REQUIRED way to configure the middleware.
The validator must implement ValidateToken, and optionally ValidateDPoPProof for DPoP support. The Auth0 validator package provides both methods automatically.
Example:
validator, _ := validator.New(...) // Supports both JWT and DPoP
middleware, err := jwtmiddleware.New(
jwtmiddleware.WithValidator(validator),
)
type TokenExtractor ¶
type TokenExtractor func(r *http.Request) (ExtractedToken, error)
TokenExtractor is a function that takes a request as input and returns an ExtractedToken containing both the token and its authorization scheme, or an error. An error should only be returned if an attempt to specify a token was found, but the information was somehow incorrectly formed. In the case where a token is simply not present, this should not be treated as an error. An empty ExtractedToken should be returned in that case.
For extractors that don't have scheme information (cookies, query params), the Scheme field should be set to AuthSchemeUnknown.
func CookieTokenExtractor ¶
func CookieTokenExtractor(cookieName string) TokenExtractor
CookieTokenExtractor builds a TokenExtractor that takes a request and extracts the token from the cookie using the passed in cookieName. Note: Cookies do not carry scheme information, so Scheme will be AuthSchemeUnknown.
func MultiTokenExtractor ¶
func MultiTokenExtractor(extractors ...TokenExtractor) TokenExtractor
MultiTokenExtractor returns a TokenExtractor that runs multiple TokenExtractors and takes the one that does not return an empty token. If a TokenExtractor returns an error that error is immediately returned.
func ParameterTokenExtractor ¶
func ParameterTokenExtractor(param string) TokenExtractor
ParameterTokenExtractor returns a TokenExtractor that extracts the token from the specified query string parameter. Note: Query parameters do not carry scheme information, so Scheme will be AuthSchemeUnknown.
type TrustedProxyConfig ¶
type TrustedProxyConfig struct {
// TrustXForwardedProto enables X-Forwarded-Proto header (https/http scheme)
TrustXForwardedProto bool
// TrustXForwardedHost enables X-Forwarded-Host header (original hostname)
TrustXForwardedHost bool
// TrustXForwardedPrefix enables X-Forwarded-Prefix header (API gateway path prefix)
TrustXForwardedPrefix bool
// TrustForwarded enables RFC 7239 Forwarded header (most secure, structured format)
TrustForwarded bool
}
TrustedProxyConfig defines which reverse proxy headers to trust.
SECURITY WARNING: Only enable when behind a trusted reverse proxy! Enabling this in direct internet-facing deployments allows header injection attacks.
When enabled, the middleware will trust forwarded headers (X-Forwarded-*, Forwarded) to reconstruct the original client request URL for DPoP HTU validation.
Design decisions and considerations: - Secure by default: nil config means NO headers are trusted - Explicit opt-in required for each header type - RFC 7239 Forwarded takes precedence over X-Forwarded-* when both are enabled - Leftmost value used for multi-proxy chains (closest to client) - Empty or malformed headers are safely ignored (falls back to direct request)
Known limitations: - Headers are assumed to be properly sanitized by the reverse proxy - No validation of header value formats (relies on reverse proxy to provide valid values) - Port numbers are stripped from host for HTU validation (per DPoP spec)
Future considerations: - Configurable header value length limits - Support for custom/non-standard forwarded headers
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package core provides framework-agnostic JWT validation logic that can be used across different transport layers (HTTP, gRPC, etc.).
|
Package core provides framework-agnostic JWT validation logic that can be used across different transport layers (HTTP, gRPC, etc.). |
|
internal
|
|
|
oidc
Package oidc provides OIDC (OpenID Connect) discovery functionality.
|
Package oidc provides OIDC (OpenID Connect) discovery functionality. |
|
Package jwks provides JWKS (JSON Web Key Set) fetching and caching for JWT validation.
|
Package jwks provides JWKS (JSON Web Key Set) fetching and caching for JWT validation. |
|
Package validator provides JWT validation using the lestrrat-go/jwx v3 library.
|
Package validator provides JWT validation using the lestrrat-go/jwx v3 library. |
