auth

package
v0.0.5 Latest Latest
Warning

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

Go to latest
Published: Sep 7, 2025 License: MIT Imports: 10 Imported by: 0

README

Authentication Package

Secure JWT authentication middleware with functional configuration and interface-based design.

Features

  • JWT validation - RFC 7519 compliant with signature verification and JWKS support
  • Time-based security - Expiration, issued-at, and not-before validation
  • Audience & scope validation - Configurable audience and scope checking
  • Token revocation - In-memory token blacklisting with automatic cleanup
  • Performance caching - Configurable token caching to reduce validation overhead
  • Interface-based design - Flexible interfaces for custom token extraction and validation
  • Functional configuration - Clean configuration with functional option pattern
  • Middleware composition - Chain and compose middleware for complex scenarios

Quick Start

package main

import (
    "net/http"
    
    "github.com/Okja-Engineering/go-service-kit/pkg/auth"
)

func main() {
    // Create JWT validator with functional options
    validator := auth.NewJWTValidator(
        auth.WithClientID("your-client-id"),
        auth.WithJWKSURL("https://your-auth-server/.well-known/jwks.json"),
        auth.WithScope("api:read"),
    )
    
    // Protected endpoint
    http.HandleFunc("/api/protected", validator.Protect(func(w http.ResponseWriter, r *http.Request) {
        // Get user ID from JWT claims
        userID, found := auth.GetUserIDFromContext(r.Context())
        if found {
            w.Write([]byte("Hello, " + userID + "!"))
        }
    }))
    
    http.ListenAndServe(":8080", nil)
}

Configuration

Functional Options
// Basic configuration
validator := auth.NewJWTValidator(
    auth.WithClientID("my-app"),
    auth.WithJWKSURL("https://auth.example.com/.well-known/jwks.json"),
)

// Advanced configuration
validator := auth.NewJWTValidator(
    auth.WithClientID("my-app"),
    auth.WithJWKSURL("https://auth.example.com/.well-known/jwks.json"),
    auth.WithScope("api:write"),
    auth.WithAllowedAlgs([]string{"RS256", "ES256"}),
    auth.WithCacheTTL(10 * time.Minute),
)
Available Options
func WithClientID(clientID string) Option
func WithJWKSURL(jwksURL string) Option
func WithScope(scope string) Option
func WithAllowedAlgs(algs []string) Option
func WithCacheTTL(ttl time.Duration) Option
func WithTokenExtractor(extractor TokenExtractor) Option
func WithClaimsValidator(validator ClaimsValidator) Option

Usage

Basic Authentication
// Create validator
validator := auth.NewJWTValidator(
    auth.WithClientID("my-app"),
    auth.WithJWKSURL("https://auth.example.com/.well-known/jwks.json"),
)

// Use as middleware
router.Use(validator.Middleware)

// Or protect individual handlers
router.Get("/api/users", validator.Protect(handleGetUsers))
Token Revocation
// Revoke a token (e.g., on logout)
validator.RevokeToken("eyJhbGciOiJIUzI1NiIs...")

// Subsequent requests with this token will be rejected
Development/Testing
// Use passthrough validator for development
validator := auth.NewPassthroughValidator()

// All requests pass through without validation

Context Integration

Getting User Information
// Get user ID from JWT claims
userID, found := auth.GetUserIDFromContext(r.Context())
if found {
    // Use userID
}

// Get all claims
claims, found := auth.GetClaimsFromContext(r.Context())
if found {
    // Access any claim
    email := claims["email"].(string)
    roles := claims["roles"].([]interface{})
}
Supported User ID Fields

The GetUserIDFromContext function looks for user ID in these claim fields:

  1. sub (standard JWT subject claim)
  2. user_id
  3. uid
  4. userid

API Reference

Core Interfaces
type Validator interface {
    Middleware(next http.Handler) http.Handler
    Protect(handler http.HandlerFunc) http.HandlerFunc
    ValidateRequest(r *http.Request) (*jwt.Token, error)
}

type TokenExtractor interface {
    ExtractToken(r *http.Request) string
}

type ClaimsValidator interface {
    ValidateClaims(claims jwt.MapClaims) error
}
Configuration
type JWTConfig struct {
    ClientID        string
    JWKSURL         string
    Scope           string
    AllowedAlgs     []string
    CacheTTL        time.Duration
    RefreshInterval time.Duration
}

func DefaultJWTConfig() *JWTConfig
func NewJWTConfig(options ...Option) *JWTConfig
Functions
func NewJWTValidator(options ...Option) (Validator, error)
func NewPassthroughValidator() Validator
func GetClaimsFromContext(ctx context.Context) (jwt.MapClaims, bool)
func GetUserIDFromContext(ctx context.Context) (string, bool)
func Chain(middlewares ...func(http.Handler) http.Handler) func(http.Handler) http.Handler
func Compose(middlewares ...func(http.Handler) http.Handler) func(http.Handler) http.Handler

Examples

Complete Authentication Setup
package main

import (
    "net/http"
    "time"
    
    "github.com/go-chi/chi/v5"
    "github.com/Okja-Engineering/go-service-kit/pkg/auth"
)

func main() {
    router := chi.NewRouter()
    
    // Create JWT validator
    validator := auth.NewJWTValidator(
        auth.WithClientID("my-api"),
        auth.WithJWKSURL("https://auth.example.com/.well-known/jwks.json"),
        auth.WithScope("api:read"),
        auth.WithAllowedAlgs([]string{"RS256", "ES256"}),
        auth.WithCacheTTL(5 * time.Minute),
    )
    
    // Public routes
    router.Get("/health", handleHealth)
    
    // Protected routes
    router.Group(func(r chi.Router) {
        r.Use(validator.Middleware)
        r.Get("/api/users", handleGetUsers)
        r.Post("/api/users", handleCreateUser)
        r.Get("/api/users/{id}", handleGetUser)
    })
    
    http.ListenAndServe(":8080", router)
}
Custom Token Extraction
// Custom token extractor for API keys
type APIKeyExtractor struct{}

func (e *APIKeyExtractor) ExtractToken(r *http.Request) string {
    return r.Header.Get("X-API-Key")
}

// Use custom extractor
validator := auth.NewJWTValidator(
    auth.WithClientID("my-app"),
    auth.WithJWKSURL("https://auth.example.com/.well-known/jwks.json"),
    auth.WithTokenExtractor(&APIKeyExtractor{}),
)
Custom Claims Validation
// Custom claims validator
type CustomValidator struct{}

func (v *CustomValidator) ValidateClaims(claims jwt.MapClaims) error {
    // Check for required role
    if roles, ok := claims["roles"].([]interface{}); ok {
        for _, role := range roles {
            if role == "admin" {
                return nil
            }
        }
    }
    return errors.New("admin role required")
}

// Use custom validator
validator := auth.NewJWTValidator(
    auth.WithClientID("my-app"),
    auth.WithJWKSURL("https://auth.example.com/.well-known/jwks.json"),
    auth.WithClaimsValidator(&CustomValidator{}),
)
Middleware Composition
// Chain multiple middleware
authChain := auth.Chain(
    validator.Middleware,
    rateLimiter.Middleware,
    logging.Middleware,
)

router.Use(authChain)

Error Handling

Error Types
type ValidationError struct {
    Code    string
    Message string
}

type ConfigurationError struct {
    Message string
}

func IsValidationError(err error) bool
func IsConfigurationError(err error) bool
Error Codes
Code Description
MISSING_TOKEN Authorization header is missing or invalid
TOKEN_REVOKED Token has been revoked
INVALID_TOKEN Token signature or format is invalid
INVALID_CLAIMS Token claims are invalid (expired, wrong audience, etc.)

Best Practices

  1. Use HTTPS - Always use HTTPS in production
  2. Configure scopes - Use specific scopes for different endpoints
  3. Set appropriate TTLs - Balance security with performance
  4. Monitor JWKS refresh - Ensure your auth server's JWKS is accessible
  5. Handle token revocation - Implement logout by revoking tokens
  6. Use strong algorithms - Prefer RS256/ES256 over HS256 for API tokens
  7. Compose middleware - Use middleware composition for complex scenarios

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Chain added in v0.0.3

func Chain(middlewares ...func(http.Handler) http.Handler) func(http.Handler) http.Handler

Chain combines multiple middleware functions

func Compose added in v0.0.3

func Compose(handlers ...func(http.HandlerFunc) http.HandlerFunc) func(http.HandlerFunc) http.HandlerFunc

Compose combines multiple handler functions

func GetClaimsFromContext

func GetClaimsFromContext(ctx context.Context) (jwt.MapClaims, bool)

GetClaimsFromContext extracts JWT claims from request context

func GetUserIDFromContext

func GetUserIDFromContext(ctx context.Context) (string, bool)

GetUserIDFromContext extracts user ID from JWT claims in context

func IsConfigurationError added in v0.0.3

func IsConfigurationError(err error) bool

IsConfigurationError checks if an error is a ConfigurationError

func IsValidationError added in v0.0.3

func IsValidationError(err error) bool

IsValidationError checks if an error is a ValidationError

Types

type CachedToken

type CachedToken struct {
	Claims    jwt.MapClaims
	ExpiresAt time.Time
	Validated time.Time
}

CachedToken represents a cached validated token

type ClaimsValidator added in v0.0.3

type ClaimsValidator interface {
	ValidateClaims(claims jwt.MapClaims) error
}

ClaimsValidator interface for flexible claims validation

type ConfigurationError added in v0.0.3

type ConfigurationError struct {
	Field   string
	Message string
}

ConfigurationError represents configuration errors

func (*ConfigurationError) Error added in v0.0.3

func (e *ConfigurationError) Error() string

type ContextKey

type ContextKey string

ContextKey is a type-safe key for context values

const (
	// JWTClaimsKey is the context key for JWT claims
	JWTClaimsKey ContextKey = "jwt_claims"
)

type JWTConfig

type JWTConfig struct {
	ClientID        string
	JWKSURL         string
	Scope           string
	AllowedAlgs     []string
	CacheTTL        time.Duration
	RefreshInterval time.Duration
}

JWTConfig holds configuration for JWT validation

func DefaultJWTConfig

func DefaultJWTConfig() *JWTConfig

DefaultJWTConfig provides secure defaults

type JWTValidator

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

JWTValidator provides hardened JWT validation with comprehensive security checks

func NewJWTValidator

func NewJWTValidator(config *JWTConfig) (*JWTValidator, error)

NewJWTValidator creates a new hardened JWT validator

func (*JWTValidator) Middleware

func (v *JWTValidator) Middleware(next http.Handler) http.Handler

Middleware returns a middleware function that validates JWT tokens

func (*JWTValidator) Protect

func (v *JWTValidator) Protect(next http.HandlerFunc) http.HandlerFunc

Protect wraps a handler function with JWT validation

func (*JWTValidator) RevokeToken

func (v *JWTValidator) RevokeToken(tokenString string)

RevokeToken marks a token as revoked

func (*JWTValidator) ValidateRequest

func (v *JWTValidator) ValidateRequest(r *http.Request) ValidationResult

ValidateRequest performs comprehensive JWT validation

type Option added in v0.0.3

type Option func(*JWTValidator)

Option is a functional option for configuring JWT validation

func WithAllowedAlgs added in v0.0.3

func WithAllowedAlgs(algs []string) Option

WithAllowedAlgs sets the allowed signing algorithms

func WithCacheTTL added in v0.0.3

func WithCacheTTL(ttl time.Duration) Option

WithCacheTTL sets the token cache TTL

func WithClaimsValidator added in v0.0.3

func WithClaimsValidator(validator ClaimsValidator) Option

WithClaimsValidator sets a custom claims validator

func WithScope added in v0.0.3

func WithScope(scope string) Option

WithScope sets the required scope

func WithTokenExtractor added in v0.0.3

func WithTokenExtractor(extractor TokenExtractor) Option

WithTokenExtractor sets a custom token extractor

type PassthroughValidator

type PassthroughValidator struct{}

PassthroughValidator for testing/development

func NewPassthroughValidator

func NewPassthroughValidator() *PassthroughValidator

func (*PassthroughValidator) Middleware

func (v *PassthroughValidator) Middleware(next http.Handler) http.Handler

func (*PassthroughValidator) Protect

type TokenExtractor added in v0.0.3

type TokenExtractor interface {
	ExtractToken(r *http.Request) string
}

TokenExtractor interface for flexible token extraction

type ValidationError added in v0.0.3

type ValidationError struct {
	Code    string
	Message string
	Err     error
}

ValidationError represents JWT validation errors

func (*ValidationError) Error added in v0.0.3

func (e *ValidationError) Error() string

Error methods for better error handling

type ValidationResult

type ValidationResult struct {
	Valid     bool
	Claims    jwt.MapClaims
	Error     string
	ErrorCode string
}

ValidationResult provides detailed validation information

type Validator added in v0.0.3

type Validator interface {
	Middleware(next http.Handler) http.Handler
	Protect(next http.HandlerFunc) http.HandlerFunc
	ValidateRequest(r *http.Request) ValidationResult
}

Validator interface defines the contract for JWT validation

Jump to

Keyboard shortcuts

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