Skip to content

go-zoox/jwt

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

40 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

JWT - JSON Web Token Library

A comprehensive Go library for creating, signing, and verifying JSON Web Tokens (JWT) with support for multiple cryptographic algorithms.

πŸš€ Features

  • Multiple Algorithm Support: HMAC, RSA, ECDSA, and RSA-PSS algorithms
  • Easy to Use: Simple API for signing and verification
  • Flexible Configuration: Customizable options for claims and timestamps
  • Comprehensive Testing: Full test coverage for all algorithms
  • Production Ready: Used in production environments
  • Performance Optimized: Key caching, object pooling, and algorithm registry
  • Builder Pattern: Fluent interface for easy JWT construction
  • Custom Error Types: Detailed error handling with context

πŸ“¦ Installation

go get github.com/go-zoox/jwt

πŸ” Supported Algorithms

Type Algorithm Description Key Type
HMAC HS256 HMAC with SHA-256 Symmetric
HMAC HS384 HMAC with SHA-384 Symmetric
HMAC HS512 HMAC with SHA-512 Symmetric
RSA RS256 RSA with SHA-256 Asymmetric
RSA RS384 RSA with SHA-384 Asymmetric
RSA RS512 RSA with SHA-512 Asymmetric
ECDSA ES256 ECDSA with SHA-256 Asymmetric
ECDSA ES384 ECDSA with SHA-384 Asymmetric
ECDSA ES512 ECDSA with SHA-512 Asymmetric
RSA-PSS PS256 RSA-PSS with SHA-256 Asymmetric
RSA-PSS PS384 RSA-PSS with SHA-384 Asymmetric
RSA-PSS PS512 RSA-PSS with SHA-512 Asymmetric

🎯 Quick Start

Basic Usage

package main

import (
    "fmt"
    "github.com/go-zoox/jwt"
)

func main() {
    // Create a JWT instance with HS256 algorithm
    j := jwt.NewHS256("your-secret-key")
    
    // Set JWT claims
    j.SetIssuer("my-app")
    j.SetSubject("user123")
    j.SetAudience("my-api")
    
    // Define payload
    payload := map[string]interface{}{
        "user_id": 123,
        "role":    "admin",
        "email":   "[email protected]",
    }
    
    // Sign the token
    token, err := j.Sign(payload)
    if err != nil {
        panic(err)
    }
    
    fmt.Println("Token:", token)
    
    // Verify the token
    jVerify := jwt.NewHS256("your-secret-key")
    verifiedPayload, err := jVerify.Verify(token)
    if err != nil {
        panic(err)
    }
    
    fmt.Println("User ID:", verifiedPayload.Get("user_id").Int64())
    fmt.Println("Role:", verifiedPayload.Get("role").String())
}

πŸ”‘ Algorithm-Specific Examples

HMAC Algorithms (HS256, HS384, HS512)

// HS256 - Most commonly used
j := jwt.NewHS256("your-secret-key")

// HS384 - Higher security
j := jwt.NewHS384("your-secret-key")

// HS512 - Highest security
j := jwt.NewHS512("your-secret-key")

RSA Algorithms (RS256, RS384, RS512)

// Generate RSA key pair (2048-bit recommended)
privateKeyPEM := `-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC7VJTUt9Us8cKB...
-----END PRIVATE KEY-----`

publicKeyPEM := `-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu1SU1LfVLPHCgX8x...
-----END PUBLIC KEY-----`

// Sign with RS256
j := jwt.NewRS256(privateKeyPEM)
token, err := j.Sign(payload)

// Verify with RS256
jVerify := jwt.New(publicKeyPEM, &jwt.Options{
    Algorithm: jwt.AlgRS256,
})
payload, err := jVerify.Verify(token)

ECDSA Algorithms (ES256, ES384, ES512)

// Generate ECDSA key pair (P-256 curve)
privateKeyPEM := `-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg...
-----END PRIVATE KEY-----`

publicKeyPEM := `-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE...
-----END PUBLIC KEY-----`

// Sign with ES256
j := jwt.NewES256(privateKeyPEM)
token, err := j.Sign(payload)

// Verify with ES256
jVerify := jwt.New(publicKeyPEM, &jwt.Options{
    Algorithm: jwt.AlgES256,
})
payload, err := jVerify.Verify(token)

RSA-PSS Algorithms (PS256, PS384, PS512)

// Generate RSA key pair (2048-bit recommended)
privateKeyPEM := `-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC7VJTUt9Us8cKB...
-----END PRIVATE KEY-----`

publicKeyPEM := `-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu1SU1LfVLPHCgX8x...
-----END PUBLIC KEY-----`

// Sign with PS256 (RSA-PSS with SHA-256)
j := jwt.NewPS256(privateKeyPEM)
token, err := j.Sign(payload)

// Verify with PS256
jVerify := jwt.New(publicKeyPEM, &jwt.Options{
    Algorithm: jwt.AlgPS256,
})
payload, err := jVerify.Verify(token)

// PS384 and PS512 work similarly
j384 := jwt.NewPS384(privateKeyPEM)
j512 := jwt.NewPS512(privateKeyPEM)

βš™οΈ Configuration Options

SignOptions

signOptions := &jwt.SignOptions{
    Algorithm: jwt.AlgHS256,    // Algorithm to use
    Issuer:    "my-app",        // iss claim
    Subject:   "user123",       // sub claim
    Audience:  "my-api",        // aud claim
    IssuedAt:  1640995200,      // iat claim (Unix timestamp)
    ExpiresAt: 1641081600,     // exp claim (Unix timestamp)
    NotBefore: 1640995200,     // nbf claim (Unix timestamp)
}

VerifyOptions

verifyOptions := &jwt.VerifyOptions{
    Issuer:   "my-app",         // Expected issuer
    Subject:  "user123",        // Expected subject
    Audience: "my-api",         // Expected audience
}

πŸ› οΈ Advanced Usage

Custom Claims

payload := map[string]interface{}{
    "user_id":    123,
    "role":       "admin",
    "permissions": []string{"read", "write", "delete"},
    "metadata": map[string]interface{}{
        "last_login": "2023-01-01T00:00:00Z",
        "ip_address": "192.168.1.1",
    },
}

Auto Timestamp Generation

j := jwt.NewHS256("secret")
j.SetIssuedAt(time.Now().Unix())           // Current time
j.SetExpiresAt(time.Now().Add(24*time.Hour).Unix()) // 24 hours from now

Token Parsing

// Parse token without verification
header, payload, err := jwt.Parse(token)
if err != nil {
    panic(err)
}

fmt.Println("Algorithm:", header.Algorithm)
fmt.Println("Type:", header.Type)
fmt.Println("User ID:", payload.Get("user_id").Int64())

Builder Pattern

// Fluent interface for building JWTs
token, err := BuildHS256("secret-key").
    WithIssuer("my-app").
    WithSubject("user123").
    WithAudience("my-api").
    WithExpiresIn(24*time.Hour).
    WithIssuedNow().
    BuildAndSign(payload)

// Or build the JWT instance first
jwt := BuildRS256(privateKey).
    WithIssuer("my-app").
    WithExpiresIn(3600).
    Build()

token, err := jwt.Sign(payload)

Custom Error Handling

token, err := jwt.Sign(payload)
if err != nil {
    if jwtErr, ok := err.(*jwt.JWTError); ok {
        switch jwtErr.Type {
        case jwt.ErrTypeInvalidKey:
            log.Printf("Invalid key: %s", jwtErr.Message)
        case jwt.ErrTypeExpiredToken:
            log.Printf("Token expired: %s", jwtErr.Message)
        case jwt.ErrTypeUnsupportedAlg:
            log.Printf("Unsupported algorithm: %s", jwtErr.Message)
        default:
            log.Printf("JWT error: %s", jwtErr.Message)
        }
    }
}

πŸ”’ Security Best Practices

Key Management

  1. HMAC Keys: Use strong, random secrets (at least 256 bits)
  2. RSA Keys: Use at least 2048-bit keys (3072-bit recommended)
  3. ECDSA Keys: P-256 curve provides equivalent security to RSA-3072
  4. RSA-PSS: Preferred over PKCS1v15 for new applications
  5. Key Rotation: Implement regular key rotation policies

Token Security

// Set short expiration times
j.SetExpiresAt(time.Now().Add(15*time.Minute).Unix())

// Use secure random secrets
secret := make([]byte, 32)
rand.Read(secret)
j := jwt.NewHS256(base64.StdEncoding.EncodeToString(secret))

// Validate all claims
verifyOptions := &jwt.VerifyOptions{
    Issuer:   "trusted-issuer",
    Audience: "my-api",
}

πŸ§ͺ Testing

Run all tests:

go test -v

Run specific algorithm tests:

# HMAC tests
go test -v -run "TestHS.*"

# RSA tests
go test -v -run "TestRS.*"

# ECDSA tests
go test -v -run "TestES.*"

# RSA-PSS tests
go test -v -run "TestPS.*"

πŸ“Š Performance

Benchmarks

Algorithm Sign (ops/sec) Verify (ops/sec) Key Size
HS256 ~50,000 ~50,000 256-bit
RS256 ~1,000 ~5,000 2048-bit
ES256 ~2,000 ~3,000 256-bit
PS256 ~800 ~4,000 2048-bit

Benchmarks on Intel i7-8700K, Go 1.21

Performance Optimizations

  • Key Caching: Parsed cryptographic keys are cached to avoid repeated parsing
  • Object Pooling: Hash functions are pooled to reduce memory allocations
  • Algorithm Registry: Centralized algorithm management for better performance
  • Constant Time Comparison: Prevents timing attacks on signature verification
# Run benchmarks
go test -bench=BenchmarkHS256Sign -benchmem
go test -bench=BenchmarkRS256Sign -benchmem
go test -bench=BenchmarkES256Sign -benchmem
go test -bench=BenchmarkPS256Sign -benchmem

πŸ”§ Key Generation

RSA Key Pair

# Generate private key
openssl genrsa -out private.pem 2048

# Extract public key
openssl rsa -in private.pem -pubout -out public.pem

ECDSA Key Pair

# Generate private key
openssl ecparam -genkey -name prime256v1 -noout -out private.pem

# Extract public key
openssl ec -in private.pem -pubout -out public.pem

πŸ“š API Reference

Constants

// Algorithm constants
jwt.AlgHS256  // "HS256"
jwt.AlgHS384  // "HS384"
jwt.AlgHS512  // "HS512"
jwt.AlgRS256  // "RS256"
jwt.AlgRS384  // "RS384"
jwt.AlgRS512  // "RS512"
jwt.AlgES256  // "ES256"
jwt.AlgES384  // "ES384"
jwt.AlgES512  // "ES512"
jwt.AlgPS256  // "PS256"
jwt.AlgPS384  // "PS384"
jwt.AlgPS512  // "PS512"

Constructor Functions

// HMAC constructors
jwt.NewHS256(secret string) Jwt
jwt.NewHS384(secret string) Jwt
jwt.NewHS512(secret string) Jwt

// RSA constructors
jwt.NewRS256(privateKey string) Jwt
jwt.NewRS384(privateKey string) Jwt
jwt.NewRS512(privateKey string) Jwt

// ECDSA constructors
jwt.NewES256(privateKey string) Jwt
jwt.NewES384(privateKey string) Jwt
jwt.NewES512(privateKey string) Jwt

// RSA-PSS constructors
jwt.NewPS256(privateKey string) Jwt
jwt.NewPS384(privateKey string) Jwt
jwt.NewPS512(privateKey string) Jwt

// Generic constructor
jwt.New(secret string, options *Options) Jwt

Core Functions

// Sign a payload
func Sign(secret string, payload map[string]any, options ...*SignOptions) (string, error)

// Verify a token
func Verify(secret string, token string, options ...*VerifyOptions) (*Header, *Value, error)

// Parse a token without verification
func Parse(token string) (*Header, *Value, error)

🀝 Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Add tests for new functionality
  5. Ensure all tests pass
  6. Submit a pull request

πŸ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

πŸ™ Acknowledgments

  • RFC 7519 - JSON Web Token (JWT)
  • RFC 7518 - JSON Web Algorithms (JWA)
  • Go standard library crypto packages

πŸ“ž Support


Made with ❀️ by the Go-Zoox team

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages