A comprehensive Go library for creating, signing, and verifying JSON Web Tokens (JWT) with support for multiple cryptographic algorithms.
- 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
go get github.com/go-zoox/jwt| 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 |
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())
}// 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")// 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)// 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)// 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)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 := &jwt.VerifyOptions{
Issuer: "my-app", // Expected issuer
Subject: "user123", // Expected subject
Audience: "my-api", // Expected audience
}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",
},
}j := jwt.NewHS256("secret")
j.SetIssuedAt(time.Now().Unix()) // Current time
j.SetExpiresAt(time.Now().Add(24*time.Hour).Unix()) // 24 hours from now// 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())// 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)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)
}
}
}- HMAC Keys: Use strong, random secrets (at least 256 bits)
- RSA Keys: Use at least 2048-bit keys (3072-bit recommended)
- ECDSA Keys: P-256 curve provides equivalent security to RSA-3072
- RSA-PSS: Preferred over PKCS1v15 for new applications
- Key Rotation: Implement regular key rotation policies
// 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",
}Run all tests:
go test -vRun 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.*"| 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
- 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# Generate private key
openssl genrsa -out private.pem 2048
# Extract public key
openssl rsa -in private.pem -pubout -out public.pem# Generate private key
openssl ecparam -genkey -name prime256v1 -noout -out private.pem
# Extract public key
openssl ec -in private.pem -pubout -out public.pem// 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"// 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// 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)- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Ensure all tests pass
- Submit a pull request
This project is licensed under the MIT License - see the LICENSE file for details.
- RFC 7519 - JSON Web Token (JWT)
- RFC 7518 - JSON Web Algorithms (JWA)
- Go standard library crypto packages
- π§ Email: [email protected]
- π Issues: GitHub Issues
- π Documentation: GoDoc
Made with β€οΈ by the Go-Zoox team