jwt

package
v1.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 5, 2026 License: Apache-2.0 Imports: 19 Imported by: 0

Documentation

Overview

Package jwt provides JSON Web Token authentication middleware for celeris.

The middleware extracts a JWT from a configurable source (header, query parameter, cookie, form field, or URL parameter), validates it using HMAC, RSA, ECDSA, EdDSA, or RSA-PSS keys, and stores the parsed token and claims in the context store under TokenKey and ClaimsKey. Failed authentication returns 401.

All public types (Token, Claims, MapClaims, RegisteredClaims, SigningMethod, etc.) are re-exported from the internal parser.

Simple usage with a symmetric HMAC secret:

server.Use(jwt.New(jwt.Config{
    SigningKey: []byte("my-secret-key"),
}))

JWKS auto-discovery (e.g. Auth0, Keycloak):

server.Use(jwt.New(jwt.Config{
    JWKSURL:     "https://example.com/.well-known/jwks.json",
    JWKSRefresh: 30 * time.Minute,
}))

Retrieving Token and Claims

token := jwt.TokenFromContext(c)
claims, ok := jwt.ClaimsFromContext[jwt.MapClaims](c)

Token Lookup

Config.TokenLookup supports comma-separated sources tried in order. Format: "source:name[:prefix]". Sources: header, query, cookie, form, param.

Custom Claims

Use Config.ClaimsFactory for custom struct claims types:

jwt.New(jwt.Config{
    SigningKey: secret,
    ClaimsFactory: func() jwt.Claims { return &MyClaims{} },
})

Creating Tokens

token, err := jwt.SignToken(jwt.SigningMethodHS256, jwt.MapClaims{
    "sub": "user-123",
    "exp": float64(time.Now().Add(time.Hour).Unix()),
}, []byte("secret"))

Security Best Practices

Always set "exp" on issued tokens. Use "aud" with WithAudience to prevent token confusion. Prefer asymmetric algorithms (RS256, ES256) in multi-service deployments. Store keys in environment variables or a secrets manager. Serve JWKS endpoints over HTTPS.

Algorithm-Key-Type Binding

  • HS256/HS384/HS512: []byte
  • RS256/RS384/RS512/PS256/PS384/PS512: *rsa.PublicKey / *rsa.PrivateKey
  • ES256/ES384/ES512: *ecdsa.PublicKey / *ecdsa.PrivateKey
  • EdDSA: ed25519.PublicKey / ed25519.PrivateKey

Skipping

Set Config.Skip to bypass dynamically, or Config.SkipPaths for exact-match path exclusions.

Index

Examples

Constants

View Source
const ClaimsKey = "jwt_claims"

ClaimsKey is the context store key for the token's claims.

View Source
const TokenKey = "jwt_token"

TokenKey is the context store key for the parsed *jwt.Token.

Variables

View Source
var (
	SigningMethodHS256 = jwtparse.SigningMethodHS256
	SigningMethodHS384 = jwtparse.SigningMethodHS384
	SigningMethodHS512 = jwtparse.SigningMethodHS512
	SigningMethodRS256 = jwtparse.SigningMethodRS256
	SigningMethodRS384 = jwtparse.SigningMethodRS384
	SigningMethodRS512 = jwtparse.SigningMethodRS512
	SigningMethodES256 = jwtparse.SigningMethodES256
	SigningMethodES384 = jwtparse.SigningMethodES384
	SigningMethodES512 = jwtparse.SigningMethodES512
	SigningMethodEdDSA = jwtparse.SigningMethodEdDSA
	SigningMethodPS256 = jwtparse.SigningMethodPS256
	SigningMethodPS384 = jwtparse.SigningMethodPS384
	SigningMethodPS512 = jwtparse.SigningMethodPS512
)

Signing method singletons.

View Source
var (
	ErrTokenMalformed        = jwtparse.ErrTokenMalformed
	ErrTokenExpired          = jwtparse.ErrTokenExpired
	ErrTokenNotValidYet      = jwtparse.ErrTokenNotValidYet
	ErrTokenSignatureInvalid = jwtparse.ErrTokenSignatureInvalid
	ErrAlgNone               = jwtparse.ErrAlgNone
	ErrTokenUnverifiable     = jwtparse.ErrTokenUnverifiable
	ErrTokenUsedBeforeIssued = jwtparse.ErrTokenUsedBeforeIssued
	ErrInvalidIssuer         = jwtparse.ErrInvalidIssuer
	ErrInvalidAudience       = jwtparse.ErrInvalidAudience
	ErrInvalidSubject        = jwtparse.ErrInvalidSubject
)

Sentinel errors from the parser.

View Source
var (
	WithValidMethods = jwtparse.WithValidMethods
	WithLeeway       = jwtparse.WithLeeway
	WithIssuer       = jwtparse.WithIssuer
	WithAudience     = jwtparse.WithAudience
	WithSubject      = jwtparse.WithSubject
)

Parser option constructors.

View Source
var ErrJWTExpired = &celeris.HTTPError{Code: 401, Message: "Unauthorized", Err: errors.New("jwt: token has expired")}

ErrJWTExpired is returned when the token's exp claim is in the past.

View Source
var ErrJWTMalformed = &celeris.HTTPError{Code: 401, Message: "Unauthorized", Err: errors.New("jwt: token is malformed")}

ErrJWTMalformed is returned when the token cannot be parsed (bad encoding, wrong number of segments, etc.).

View Source
var ErrTokenInvalid = &celeris.HTTPError{Code: 401, Message: "Unauthorized", Err: errors.New("jwt: invalid or expired token")}

ErrTokenInvalid is returned when the token fails validation for reasons other than expiration or malformation (e.g., bad signature, unknown kid).

View Source
var ErrTokenMissing = &celeris.HTTPError{Code: 401, Message: "Unauthorized", Err: errors.New("jwt: missing or malformed token")}

ErrTokenMissing is returned when no token is found in the request.

View Source
var ErrUnauthorized = celeris.NewHTTPError(401, "Unauthorized")

ErrUnauthorized is returned when authentication fails.

Functions

func ClaimsFromContext

func ClaimsFromContext[T jwtparse.Claims](c *celeris.Context) (T, bool)

ClaimsFromContext returns the token claims from the context store, typed to the requested claims type T, using the default ClaimsKey. Returns the zero value and false if no claims were stored or the type assertion fails. If the middleware was configured with a custom ClaimsContextKey, use ClaimsFromContextWithKey instead.

Example
package main

import (
	"github.com/goceleris/celeris"

	"github.com/goceleris/celeris/middleware/jwt"
)

func main() {
	// Retrieve typed claims in a downstream handler.
	_ = func(c *celeris.Context) error {
		claims, ok := jwt.ClaimsFromContext[jwt.MapClaims](c)
		if !ok {
			return c.String(401, "no claims")
		}
		sub, _ := claims["sub"].(string)
		return c.String(200, "Hello %s", sub)
	}
}

func ClaimsFromContextWithKey

func ClaimsFromContextWithKey[T jwtparse.Claims](c *celeris.Context, key string) (T, bool)

ClaimsFromContextWithKey returns the token claims from the context store, typed to the requested claims type T, using the specified key. Returns the zero value and false if no claims were stored or the type assertion fails.

func New

func New(config ...Config) celeris.HandlerFunc

New creates a JWT authentication middleware with the given config.

Example
package main

import (
	"github.com/goceleris/celeris/middleware/jwt"
)

func main() {
	// Simple HMAC authentication with a shared secret.
	_ = jwt.New(jwt.Config{
		SigningKey: []byte("my-secret-key"),
	})
}
Example (ClaimsFactory)
package main

import (
	"github.com/goceleris/celeris/middleware/jwt"
)

type MyClaims struct {
	jwt.RegisteredClaims
	Role string `json:"role"`
}

func main() {
	// Use ClaimsFactory for custom struct claims to avoid data races.
	_ = jwt.New(jwt.Config{
		SigningKey: []byte("secret"),
		ClaimsFactory: func() jwt.Claims {
			return &MyClaims{}
		},
	})
}
Example (CustomContextKeys)
package main

import (
	"github.com/goceleris/celeris/middleware/jwt"
)

func main() {
	// Store token and claims under custom context keys.
	_ = jwt.New(jwt.Config{
		SigningKey:       []byte("secret"),
		TokenContextKey:  "my_token",
		ClaimsContextKey: "my_claims",
	})
}
Example (CustomKeyFunc)
package main

import (
	"github.com/goceleris/celeris/middleware/jwt"
)

func main() {
	// Full control over key resolution.
	_ = jwt.New(jwt.Config{
		SigningKey: []byte("unused"), // satisfies validation
		KeyFunc: func(t *jwt.Token) (any, error) {
			// Custom key lookup logic.
			return []byte("dynamic-secret"), nil
		},
	})
}
Example (ErrorHandler)
package main

import (
	"github.com/goceleris/celeris"

	"github.com/goceleris/celeris/middleware/jwt"
)

func main() {
	// Custom error handler for JSON responses.
	_ = jwt.New(jwt.Config{
		SigningKey: []byte("secret"),
		ErrorHandler: func(c *celeris.Context, err error) error {
			return c.JSON(401, map[string]string{"error": err.Error()})
		},
	})
}
Example (Jwks)
package main

import (
	"time"

	"github.com/goceleris/celeris/middleware/jwt"
)

func main() {
	// JWKS auto-discovery (e.g. Auth0, Keycloak).
	_ = jwt.New(jwt.Config{
		JWKSURL:     "https://example.com/.well-known/jwks.json",
		JWKSRefresh: 30 * time.Minute,
	})
}
Example (MultipleSources)
package main

import (
	"github.com/goceleris/celeris/middleware/jwt"
)

func main() {
	// Try header first, then query, then cookie.
	_ = jwt.New(jwt.Config{
		SigningKey:  []byte("secret"),
		TokenLookup: "header:Authorization:Bearer ,query:token,cookie:jwt",
	})
}
Example (QueryParam)
package main

import (
	"github.com/goceleris/celeris/middleware/jwt"
)

func main() {
	// Extract token from query parameter instead of header.
	_ = jwt.New(jwt.Config{
		SigningKey:  []byte("secret"),
		TokenLookup: "query:token",
	})
}
Example (SigningKeys)
package main

import (
	"github.com/goceleris/celeris/middleware/jwt"
)

func main() {
	// Key rotation with kid-based key selection.
	_ = jwt.New(jwt.Config{
		SigningKeys: map[string]any{
			"key-1": []byte("secret-1"),
			"key-2": []byte("secret-2"),
		},
	})
}
Example (TokenProcessorFunc)
package main

import (
	"github.com/goceleris/celeris/middleware/jwt"
)

func main() {
	// JWE decryption: TokenProcessorFunc decrypts the outer JWE envelope
	// before the inner JWS is parsed and validated by the middleware.
	_ = jwt.New(jwt.Config{
		SigningKey: []byte("signing-secret"),
		TokenProcessorFunc: func(token string) (string, error) {
			// In a real application, this would decrypt a JWE compact
			// serialization (5-part dot-separated) using a private key
			// or shared symmetric key, returning the inner JWS token.
			//
			// Example with a JWE library (pseudocode):
			//   privKey := loadDecryptionKey()
			//   jws, err := jwe.Decrypt([]byte(token), privKey)
			//   return string(jws), err
			//
			// For this example, we simulate by stripping a "jwe:" prefix.
			if len(token) > 4 && token[:4] == "jwe:" {
				return token[4:], nil
			}
			return token, nil
		},
	})
}

func SignToken

func SignToken(method SigningMethod, claims Claims, key any) (string, error)

SignToken creates and signs a new JWT.

func TokenFromContext

func TokenFromContext(c *celeris.Context) *jwtparse.Token

TokenFromContext returns the parsed JWT token from the context store using the default TokenKey. Returns nil if no token was stored. If the middleware was configured with a custom TokenContextKey, use TokenFromContextWithKey instead.

Example
package main

import (
	"github.com/goceleris/celeris"

	"github.com/goceleris/celeris/middleware/jwt"
)

func main() {
	// Retrieve the raw parsed token in a downstream handler.
	_ = func(c *celeris.Context) error {
		token := jwt.TokenFromContext(c)
		if token == nil {
			return c.String(401, "no token")
		}
		return c.String(200, "Algorithm: %s", token.Method.Alg())
	}
}

func TokenFromContextWithKey

func TokenFromContextWithKey(c *celeris.Context, key string) *jwtparse.Token

TokenFromContextWithKey returns the parsed JWT token from the context store using the specified key. Returns nil if no token was stored.

Types

type Audience

type Audience = jwtparse.Audience

Audience is a list of recipients the JWT is intended for.

type Claims

type Claims = jwtparse.Claims

Claims is the interface satisfied by all JWT claims types.

type Config

type Config struct {
	// Skip defines a function to skip this middleware for certain requests.
	Skip func(c *celeris.Context) bool

	// SkipPaths lists paths to skip (exact match).
	SkipPaths []string

	// SigningKey is the key used to verify tokens. For HMAC this is a
	// []byte secret; for RSA/ECDSA this is the public key.
	SigningKey any

	// SigningKeys maps kid (Key ID) to verification key for key rotation.
	// When set, the token's "kid" header selects the key.
	SigningKeys map[string]any

	// SigningMethod is the expected signing algorithm.
	// Default: jwt.SigningMethodHS256.
	SigningMethod jwtparse.SigningMethod

	// ValidMethods restricts the allowed signing algorithms.
	// Default: []string{SigningMethod.Alg()}.
	ValidMethods []string

	// TokenLookup defines where to extract the token. Comma-separated
	// sources are tried in order. Format: "source:name[:prefix]".
	// Supported sources: header, query, cookie, form, param.
	// Default: "header:Authorization:Bearer ".
	TokenLookup string

	// Claims is the template for the claims type. The middleware clones
	// this for each request via [cloneClaims]. For built-in types
	// ([MapClaims], *[RegisteredClaims]) this is zero-cost. For custom
	// struct types, reflect.New is used to create a fresh zero-value
	// instance -- the template's field values are NOT copied. For
	// maximum control and to avoid reflect overhead, use ClaimsFactory
	// instead. Default: jwt.MapClaims{}.
	Claims jwtparse.Claims

	// ClaimsFactory creates a fresh Claims instance per request. When set,
	// this takes precedence over the Claims template field. Use this for
	// custom struct claims types to avoid data races.
	ClaimsFactory func() jwtparse.Claims

	// KeyFunc is a custom key function that overrides SigningKey/SigningKeys.
	KeyFunc jwtparse.Keyfunc

	// JWKSURL is a URL for JWKS auto-discovery (e.g. Auth0, Keycloak).
	// When JWKSURLs is also set, this URL is prepended to that list.
	JWKSURL string

	// JWKSURLs is a list of JWKS URLs for multi-provider federation.
	// When a token's kid is not found in one provider's keyset, the
	// next URL's keys are tried in order. If JWKSURL is also set, it
	// is treated as the first entry.
	JWKSURLs []string

	// JWKSRefresh is the interval for re-fetching the JWKS keyset.
	// Default: 1h.
	JWKSRefresh time.Duration

	// JWKSPreload controls whether JWKS keys are fetched eagerly at
	// middleware creation time. When nil (default) or pointing to true,
	// Preload is enabled and the first request avoids a blocking network
	// call. Set to a pointer to false to disable preloading (lazy fetch
	// on first request). If preload fails, a warning is logged and the
	// middleware falls back to lazy fetching.
	JWKSPreload *bool

	// TokenProcessorFunc is called on the raw token string after extraction
	// but before parsing. Use it for decryption, decompression, or other
	// transformations. If it returns an error, the middleware returns
	// ErrTokenInvalid wrapping that error.
	//
	// The returned string must be a valid compact JWS (3-part
	// dot-separated). Returning an empty string or a non-JWS value will
	// cause a parse error. The original raw token is NOT preserved;
	// Token.Raw will contain the transformed value.
	TokenProcessorFunc func(token string) (string, error)

	// TokenContextKey overrides the context store key for the parsed token.
	// Default: "jwt_token" (TokenKey).
	TokenContextKey string

	// ClaimsContextKey overrides the context store key for the claims.
	// Default: "jwt_claims" (ClaimsKey).
	ClaimsContextKey string

	// ParseOptions provides additional parser options (e.g., WithLeeway,
	// WithIssuer, WithAudience) appended after the default ValidMethods
	// option. This allows fine-grained control over the JWT parser without
	// needing a custom KeyFunc.
	ParseOptions []jwtparse.ParserOption

	// ErrorHandler handles authentication failures. Receives the error
	// and returns the error to propagate. Default: returns the error as-is.
	ErrorHandler func(c *celeris.Context, err error) error

	// SuccessHandler is called after successful token validation, before
	// c.Next(). Use for logging, metrics, or enriching the context.
	SuccessHandler func(c *celeris.Context)

	// ContinueOnIgnoredError, when true, causes the middleware to call
	// c.Next() when ErrorHandler returns nil. By default (false), when
	// ErrorHandler returns nil the middleware returns nil immediately
	// without calling c.Next(), short-circuiting the handler chain.
	// Note: when false and ErrorHandler returns nil, the middleware
	// itself returns nil (not the original error). The framework's
	// outer handler loop then runs downstream handlers independently;
	// errors from those handlers are NOT propagated through this
	// middleware's return value. Enable ContinueOnIgnoredError to
	// explicitly call c.Next() and propagate downstream errors.
	ContinueOnIgnoredError bool
}

Config defines the JWT middleware configuration.

type Header = jwtparse.Header

Header is the parsed JWT JOSE header (alg, typ, kid, etc.).

type Keyfunc

type Keyfunc = jwtparse.Keyfunc

Keyfunc is the callback used to supply the verification key.

type MapClaims

type MapClaims = jwtparse.MapClaims

MapClaims is an unstructured claims map.

type NumericDate

type NumericDate = jwtparse.NumericDate

NumericDate represents a JSON numeric date value (Unix timestamp).

func NewNumericDate

func NewNumericDate(t time.Time) *NumericDate

NewNumericDate creates a NumericDate from a time.Time.

type ParserOption

type ParserOption = jwtparse.ParserOption

ParserOption configures the JWT parser.

type RegisteredClaims

type RegisteredClaims = jwtparse.RegisteredClaims

RegisteredClaims contains the registered (standard) JWT claim fields.

type SigningMethod

type SigningMethod = jwtparse.SigningMethod

SigningMethod is the interface for JWT signing algorithms.

type Token

type Token = jwtparse.Token

Token and related type aliases re-exported from the internal parser.

Directories

Path Synopsis
internal
jwtparse
Package jwtparse implements a zero-allocation JWT parser and signer.
Package jwtparse implements a zero-allocation JWT parser and signer.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL