jwt

package
v0.3.5 Latest Latest
Warning

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

Go to latest
Published: Feb 17, 2026 License: Apache-2.0 Imports: 9 Imported by: 0

Documentation

Overview

Package jwt provides RFC 7519 compliant JSON Web Token implementation using HMAC-SHA256.

This package includes generation, validation, and parsing of JWTs with support for standard claims and custom payload structures. All operations use constant-time comparisons to prevent timing attacks and implement security best practices.

Features

- RFC 7519 compliant JWT implementation - HMAC-SHA256 signing (secure and performant) - Standard claims validation (exp, nbf, iat) - Custom claims support with any JSON-serializable type - Constant-time signature verification - Built-in temporal claim validation

Usage

Basic JWT service setup:

// Create service with signing key (should be cryptographically secure)
service, err := jwt.New(jwt.Config{SigningKey: "your-256-bit-secret"})
if err != nil {
	log.Fatal(err)
}

Generating tokens with standard claims:

claims := jwt.StandardClaims{
	Subject:   "user123",
	Issuer:    "myapp",
	Audience:  "api",
	ExpiresAt: time.Now().Add(time.Hour).Unix(),
	IssuedAt:  time.Now().Unix(),
}

token, err := service.Generate(claims)
if err != nil {
	log.Fatal(err)
}

Generating tokens with custom claims:

type CustomClaims struct {
	jwt.StandardClaims
	UserID   int    `json:"user_id"`
	Username string `json:"username"`
	Role     string `json:"role"`
}

claims := CustomClaims{
	StandardClaims: jwt.StandardClaims{
		Subject:   "user123",
		ExpiresAt: time.Now().Add(time.Hour).Unix(),
		IssuedAt:  time.Now().Unix(),
	},
	UserID:   123,
	Username: "john.doe",
	Role:     "admin",
}

token, err := service.Generate(claims)
if err != nil {
	log.Fatal(err)
}

Parsing and validating tokens:

var claims CustomClaims
err := service.Parse(token, &claims)
if err != nil {
	switch {
	case errors.Is(err, jwt.ErrExpiredToken):
		log.Println("Token has expired")
	case errors.Is(err, jwt.ErrInvalidSignature):
		log.Println("Token signature is invalid")
	default:
		log.Printf("Token parsing failed: %v", err)
	}
	return
}

log.Printf("Valid token for user: %s (ID: %d)", claims.Username, claims.UserID)

HTTP Middleware Example

func JWTMiddleware(service *jwt.Service) func(http.Handler) http.Handler {
	return func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			authHeader := r.Header.Get("Authorization")
			if authHeader == "" {
				http.Error(w, "Missing Authorization header", http.StatusUnauthorized)
				return
			}

			// Extract Bearer token
			token := strings.TrimPrefix(authHeader, "Bearer ")
			if token == authHeader {
				http.Error(w, "Invalid Authorization format", http.StatusUnauthorized)
				return
			}

			var claims CustomClaims
			if err := service.Parse(token, &claims); err != nil {
				http.Error(w, "Invalid token", http.StatusUnauthorized)
				return
			}

			// Add claims to request context
			ctx := context.WithValue(r.Context(), "claims", claims)
			next.ServeHTTP(w, r.WithContext(ctx))
		})
	}
}

Security Best Practices

Signing key requirements:

  • Use at least 32 bytes (256 bits) for HMAC-SHA256
  • Generate using cryptographically secure random source
  • Store securely (environment variables, key management service)
  • Rotate keys regularly

Token expiration:

  • Always set ExpiresAt for security tokens
  • Use short expiration times (15-60 minutes) for access tokens
  • Implement refresh token mechanism for long-lived sessions
  • Consider NotBefore (nbf) for tokens issued for future use

Validation considerations:

  • Always validate signature before trusting claims
  • Check expiration in addition to signature
  • Validate audience (aud) claim when using multiple services
  • Implement token blacklisting for logout/revocation

Standard Claims

The package supports all RFC 7519 registered claims:

  • jti (JWT ID): Unique identifier, useful for token blacklisting
  • sub (Subject): Usually user ID or entity identifier
  • iss (Issuer): Identifies who issued the token
  • aud (Audience): Intended recipients of the token
  • exp (Expiration): Unix timestamp when token expires
  • nbf (Not Before): Unix timestamp when token becomes valid
  • iat (Issued At): Unix timestamp when token was created

Error Handling

The package provides specific error types for different failure modes:

  • ErrInvalidToken: Malformed token structure or nbf validation failure
  • ErrExpiredToken: Token past expiration time
  • ErrInvalidSignature: Signature verification failed
  • ErrUnexpectedSigningMethod: Algorithm mismatch (security)
  • ErrInvalidSigningMethod: Invalid signing method (legacy)
  • ErrMissingSigningKey: Service created without key
  • ErrInvalidSigningKey: Invalid signing key (available)
  • ErrInvalidClaims: Invalid claims (available)
  • ErrMissingClaims: Generate called with nil claims

Performance Characteristics

- Token generation: ~50-100 µs (dominated by JSON marshaling) - Token parsing: ~100-200 µs (includes signature verification) - Memory usage: ~1-2 KB per token (depends on claims size) - HMAC-SHA256 is significantly faster than RSA signatures - Base64 encoding/decoding is optimized and minimal overhead

Algorithm Choice

HMAC-SHA256 is chosen for this implementation because:

  • Symmetric key operation (simpler key management)
  • High performance (much faster than RSA)
  • Strong security properties
  • Widespread support and standardization
  • Suitable for most web application use cases

Consider RSA/ECDSA for scenarios requiring:

  • Public key verification (microservices)
  • Key distribution to untrusted parties
  • Integration with existing PKI infrastructure

Index

Constants

View Source
const (
	HeaderType      = "JWT"
	HeaderAlgorithm = "HS256" // HMAC-SHA256 chosen for security/performance balance
)

JWT header constants required by RFC 7519

Variables

View Source
var (
	ErrInvalidToken            = errors.New("jwt: invalid token")
	ErrExpiredToken            = errors.New("jwt: token is expired")
	ErrInvalidSigningMethod    = errors.New("jwt: invalid signing method")
	ErrMissingSigningKey       = errors.New("jwt: missing signing key")
	ErrInvalidSigningKey       = errors.New("jwt: invalid signing key")
	ErrInvalidClaims           = errors.New("jwt: invalid claims")
	ErrMissingClaims           = errors.New("jwt: missing claims")
	ErrInvalidSignature        = errors.New("jwt: invalid signature")
	ErrUnexpectedSigningMethod = errors.New("jwt: unexpected signing method")
)

Functions

This section is empty.

Types

type Config

type Config struct {
	SigningKey string `env:"SIGNING_KEY,required"`
}

Config holds JWT service configuration.

type Header struct {
	Type      string `json:"typ"`
	Algorithm string `json:"alg"`
}

Header represents the JWT header as defined in RFC 7515

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service handles JWT token generation and validation using HMAC-SHA256. The signing key is kept in memory only and should be cryptographically secure.

func New

func New(cfg Config) (*Service, error)

New creates a new JWT service with the provided configuration. The signing key should be at least 32 bytes for adequate security with HMAC-SHA256.

func (*Service) Generate

func (s *Service) Generate(claims any) (string, error)

Generate creates a JWT token with the given claims. Accepts any JSON-serializable claims structure and returns a signed JWT string.

func (*Service) Parse

func (s *Service) Parse(tokenString string, claims any) error

Parse validates a JWT token and unmarshals its claims into the provided structure. Performs cryptographic verification, algorithm validation, and temporal claim checks.

type StandardClaims

type StandardClaims struct {
	ID        string `json:"jti,omitempty"` // JWT ID - unique identifier for preventing token reuse
	Subject   string `json:"sub,omitempty"` // Subject - typically user ID or entity identifier
	Issuer    string `json:"iss,omitempty"` // Issuer - identifies who issued the token
	Audience  string `json:"aud,omitempty"` // Audience - intended recipient(s) of the token
	ExpiresAt int64  `json:"exp,omitempty"` // Expiration time - Unix timestamp when token expires
	NotBefore int64  `json:"nbf,omitempty"` // Not before - Unix timestamp when token becomes valid
	IssuedAt  int64  `json:"iat,omitempty"` // Issued at - Unix timestamp when token was created
}

StandardClaims represents the registered JWT claims defined in RFC 7519 Section 4.1. All fields use Unix timestamps for temporal claims to ensure consistent validation.

func (StandardClaims) Valid

func (c StandardClaims) Valid() error

Valid validates the temporal claims against current time. Zero values are treated as unset (per RFC 7519) and are ignored during validation.

Jump to

Keyboard shortcuts

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