auth

package
v0.19.0 Latest Latest
Warning

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

Go to latest
Published: Feb 27, 2026 License: MIT Imports: 8 Imported by: 0

README

Auth

Comprehensive authentication package supporting JWT and PASETO tokens with both symmetric (local) and asymmetric (public) key operations.

Overview

This package provides robust token-based authentication solutions with support for:

  • JWT (JSON Web Tokens) with HMAC and RSA/ECDSA signatures
  • PASETO (Platform-Agnostic Security Tokens) v4
  • Access and refresh token patterns
  • Custom claims support

For detailed implementation information, see JWT_IMPLEMENTATION.md.

Installation

go get github.com/maadiii/goutils/auth

Features

  • 🔐 JWT Local (HMAC-SHA256)
  • 🔑 JWT Public (RSA/ECDSA)
  • 🛡️ PASETO Local (symmetric)
  • 📝 PASETO Public (asymmetric)
  • ⏰ Access & Refresh token support
  • 🎯 Custom claims
  • ✅ Token validation

Usage

JWT Local (Symmetric - HMAC)

Best for single-server applications or when all services share the same secret.

package main

import (
    "fmt"
    "time"

    "github.com/maadiii/goutils/auth"
)

func main() {
    // Configure JWT Local
    config := auth.JWTLocalConfig{
        Issuer:     "my-app",
        AccessKey:  []byte("your-secret-access-key-min-32-bytes"),
        RefreshKey: []byte("your-secret-refresh-key-min-32-bytes"),
        AccessTTL:  15 * time.Minute,
        RefreshTTL: 7 * 24 * time.Hour,
    }

    jwtLocal := auth.NewJWTLocal(config)

    // Generate access token
    accessToken, err := jwtLocal.GenerateAccessToken("user123", map[string]interface{}{
        "email": "user@example.com",
        "role":  "admin",
    })
    if err != nil {
        panic(err)
    }

    fmt.Println("Access Token:", accessToken)

    // Verify and extract claims
    claims, err := jwtLocal.VerifyAccessToken(accessToken)
    if err != nil {
        panic(err)
    }

    fmt.Printf("User ID: %s\n", claims.Subject)
    fmt.Printf("Email: %v\n", claims.CustomClaims["email"])
}
JWT Public (Asymmetric - RSA/ECDSA)

Best for microservices where different services need to verify tokens without sharing secrets.

// Generate RSA key pair
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
    panic(err)
}

config := auth.JWTPublicConfig{
    Issuer:         "my-app",
    AccessPrivate:  privateKey,
    RefreshPrivate: privateKey,
    AccessTTL:      15 * time.Minute,
    RefreshTTL:     7 * 24 * time.Hour,
}

jwtPublic := auth.NewJWTPublic(config)

// Generate token
token, err := jwtPublic.GenerateAccessToken("user123", map[string]interface{}{
    "permissions": []string{"read", "write"},
})

// Verify with public key
claims, err := jwtPublic.VerifyAccessToken(token)
PASETO Local (Symmetric)

Modern alternative to JWT with better security defaults.

// Create PASETO Local authenticator
// Key must be exactly 32 bytes
secretKey := []byte("your-32-byte-secret-key-here!")

pasetoLocal := auth.NewPasetoLocal(secretKey)

// Generate access token
accessToken, err := pasetoLocal.GenerateAccessToken(
    "user123",
    "my-app",
    "my-service",
    15*time.Minute,
    map[string]interface{}{
        "email": "user@example.com",
        "plan":  "premium",
    },
)

// Verify token
claims, err := pasetoLocal.VerifyAccessToken(accessToken)
if err != nil {
    panic(err)
}

fmt.Printf("Subject: %s\n", claims.Subject)
fmt.Printf("Email: %v\n", claims.CustomClaims["email"])
PASETO Public (Asymmetric)

PASETO with public-key cryptography using Ed25519.

import "crypto/ed25519"

// Generate Ed25519 key pair
publicKey, privateKey, err := ed25519.GenerateKey(nil)
if err != nil {
    panic(err)
}

pasetoPublic := auth.NewPasetoPublic(privateKey, publicKey)

// Generate token
token, err := pasetoPublic.GenerateAccessToken(
    "user123",
    "my-app",
    "my-service",
    15*time.Minute,
    map[string]interface{}{
        "department": "engineering",
    },
)

// Anyone with the public key can verify
claims, err := pasetoPublic.VerifyAccessToken(token)
Refresh Tokens

All authenticators support refresh token patterns:

// Generate refresh token (longer TTL)
refreshToken, err := jwtLocal.GenerateRefreshToken("user123", nil)

// Later, verify refresh token
claims, err := jwtLocal.VerifyRefreshToken(refreshToken)
if err != nil {
    // Refresh token expired or invalid
    // User needs to login again
}

// Generate new access token
newAccessToken, err := jwtLocal.GenerateAccessToken(
    claims.Subject,
    claims.CustomClaims,
)

Token Types

JWT Local
  • Algorithm: HMAC-SHA256
  • Use Case: Single server or shared secret environment
  • Key Type: Symmetric (byte slice)
  • Performance: Fast
  • Distribution: Requires secure key distribution
JWT Public
  • Algorithm: RSA or ECDSA
  • Use Case: Microservices, distributed systems
  • Key Type: Asymmetric (private/public key pair)
  • Performance: Slower than symmetric
  • Distribution: Only public key needs distribution
PASETO Local
  • Algorithm: XChaCha20-Poly1305
  • Use Case: Modern alternative to JWT
  • Key Type: Symmetric (32 bytes)
  • Security: Better defaults than JWT
  • Format: Not compatible with JWT
PASETO Public
  • Algorithm: Ed25519
  • Use Case: Modern distributed systems
  • Key Type: Asymmetric (Ed25519 keys)
  • Performance: Fast signature verification
  • Format: Not compatible with JWT

API Reference

JWT Local
type JWTLocal struct { }

func NewJWTLocal(config JWTLocalConfig) *JWTLocal
func (j *JWTLocal) GenerateAccessToken(subject string, claims map[string]interface{}) (string, error)
func (j *JWTLocal) GenerateRefreshToken(subject string, claims map[string]interface{}) (string, error)
func (j *JWTLocal) VerifyAccessToken(token string) (*JWTLocalClaims, error)
func (j *JWTLocal) VerifyRefreshToken(token string) (*JWTLocalClaims, error)
JWT Public
type JWTPublic struct { }

func NewJWTPublic(config JWTPublicConfig) *JWTPublic
func (j *JWTPublic) GenerateAccessToken(subject string, claims map[string]interface{}) (string, error)
func (j *JWTPublic) VerifyAccessToken(token string) (*JWTPublicClaims, error)
// ... refresh token methods
PASETO Local
type PasetoLocal struct { }

func NewPasetoLocal(secretKey []byte) *PasetoLocal
func (p *PasetoLocal) GenerateAccessToken(subject, issuer, audience string, ttl time.Duration, claims map[string]interface{}) (string, error)
func (p *PasetoLocal) VerifyAccessToken(token string) (*PasetoLocalClaims, error)
// ... refresh token methods
PASETO Public
type PasetoPublic struct { }

func NewPasetoPublic(privateKey ed25519.PrivateKey, publicKey ed25519.PublicKey) *PasetoPublic
func (p *PasetoPublic) GenerateAccessToken(subject, issuer, audience string, ttl time.Duration, claims map[string]interface{}) (string, error)
func (p *PasetoPublic) VerifyAccessToken(token string) (*PasetoPublicClaims, error)

Security Best Practices

  1. Key Management

    • Never commit secrets to version control
    • Use environment variables or secure vaults
    • Rotate keys periodically
    • Use minimum 32 bytes for symmetric keys
  2. Token Lifetime

    • Keep access tokens short-lived (15-30 minutes)
    • Refresh tokens can be longer (days/weeks)
    • Implement token revocation for sensitive operations
  3. Claims

    • Don't store sensitive data in tokens
    • Tokens are base64-encoded, not encrypted
    • Validate all claims on verification
  4. HTTPS Only

    • Always transmit tokens over HTTPS
    • Use secure cookie flags in browsers

Choosing the Right Authenticator

Feature JWT Local JWT Public PASETO Local PASETO Public
Speed ⚡⚡⚡ ⚡⚡ ⚡⚡⚡ ⚡⚡⚡
Security ✅✅ ✅✅✅ ✅✅✅
Microservices
Standard JWT JWT PASETO PASETO
Compatibility High High Low Low

Testing

Run tests:

go test -v ./auth/...

License

MIT License - see LICENSE for details

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func GenerateRSAKeyPair

func GenerateRSAKeyPair() (*rsa.PrivateKey, *rsa.PublicKey, error)

GenerateRSAKeyPair generates a new RSA 2048-bit key pair.

Types

type JWTLocal

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

JWTLocal generates and validates JWT tokens with HMAC signatures for access/refresh.

func NewJWTLocal

func NewJWTLocal(cfg JWTLocalConfig) (*JWTLocal, error)

NewJWTLocal builds a JWTLocal with distinct keys and TTLs for access and refresh tokens. Keys can be any length but should be at least 32 bytes for HS256, 64 bytes for HS512.

func (*JWTLocal) Generate

func (j *JWTLocal) Generate(subject, audience string, customClaims map[string]any) (Tokens, error)

Generate issues a new pair of access and refresh JWT tokens for the given subject and audience. customClaims is an optional map of additional claims to include in both tokens.

func (*JWTLocal) ValidateAccess

func (j *JWTLocal) ValidateAccess(token string) (JWTLocalClaims, error)

ValidateAccess parses and validates an access token, returning its claims.

func (*JWTLocal) ValidateRefresh

func (j *JWTLocal) ValidateRefresh(token string) (JWTLocalClaims, error)

ValidateRefresh parses and validates a refresh token, returning its claims.

type JWTLocalClaims

type JWTLocalClaims struct {
	Subject      string
	Audience     string
	Issuer       string
	ExpiresAt    time.Time
	IssuedAt     time.Time
	NotBefore    time.Time
	TokenType    JWTLocalTokenType
	CustomClaims map[string]any
}

JWTLocalClaims captures the essential claims we expose to callers.

type JWTLocalConfig

type JWTLocalConfig struct {
	Issuer     string
	AccessKey  []byte
	RefreshKey []byte
	AccessTTL  time.Duration
	RefreshTTL time.Duration
}

JWTLocalConfig holds configuration for JWT local token generation using HMAC.

type JWTLocalTokenType

type JWTLocalTokenType string

JWTLocalTokenType distinguishes access vs refresh tokens.

const (
	JWTAccessToken  JWTLocalTokenType = "access"
	JWTRefreshToken JWTLocalTokenType = "refresh"
)

type JWTPublic

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

JWTPublic generates and validates JWT tokens with RSA signatures for access/refresh.

func NewJWTPublic

func NewJWTPublic(cfg JWTPublicConfig) (*JWTPublic, error)

NewJWTPublic builds a JWTPublic with distinct RSA key pairs for access and refresh tokens.

func (*JWTPublic) Generate

func (j *JWTPublic) Generate(subject, audience string, customClaims map[string]any) (Tokens, error)

Generate issues a new pair of access and refresh JWT tokens for the given subject and audience. customClaims is an optional map of additional claims to include in both tokens.

func (*JWTPublic) ValidateAccess

func (j *JWTPublic) ValidateAccess(token string) (JWTPublicClaims, error)

ValidateAccess parses and validates an access token, returning its claims.

func (*JWTPublic) ValidateRefresh

func (j *JWTPublic) ValidateRefresh(token string) (JWTPublicClaims, error)

ValidateRefresh parses and validates a refresh token, returning its claims.

type JWTPublicClaims

type JWTPublicClaims struct {
	Subject      string
	Audience     string
	Issuer       string
	ExpiresAt    time.Time
	IssuedAt     time.Time
	NotBefore    time.Time
	TokenType    JWTPublicTokenType
	CustomClaims map[string]any
}

JWTPublicClaims captures the essential claims we expose to callers.

type JWTPublicConfig

type JWTPublicConfig struct {
	Issuer            string
	AccessPrivateKey  *rsa.PrivateKey
	AccessPublicKey   *rsa.PublicKey
	RefreshPrivateKey *rsa.PrivateKey
	RefreshPublicKey  *rsa.PublicKey
	AccessTTL         time.Duration
	RefreshTTL        time.Duration
}

JWTPublicConfig holds configuration for JWT public (asymmetric) token generation using RSA.

type JWTPublicTokenType

type JWTPublicTokenType string

JWTPublicTokenType distinguishes access vs refresh tokens.

const (
	JWTPublicAccessToken  JWTPublicTokenType = "access"
	JWTPublicRefreshToken JWTPublicTokenType = "refresh"
)

type LocalClaims

type LocalClaims struct {
	Subject      string
	Audience     string
	Issuer       string
	JTI          string
	ExpiresAt    time.Time
	IssuedAt     time.Time
	NotBefore    time.Time
	TokenType    LocalTokenType
	CustomClaims map[string]any
}

LocalClaims captures the essential claims we expose to callers.

type LocalPaseto

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

LocalPaseto generates and validates PASETO v4 local tokens for access/refresh.

func NewLocalPaseto

func NewLocalPaseto(cfg LocalPasetoConfig) (*LocalPaseto, error)

func (*LocalPaseto) Generate

func (p *LocalPaseto) Generate(subject, audience string, customClaims map[string]any) (Tokens, error)

Generate issues a new pair of access and refresh tokens for the given subject and audience. customClaims is an optional map of additional claims to include in both tokens.

func (*LocalPaseto) ValidateAccess

func (p *LocalPaseto) ValidateAccess(token string) (LocalClaims, error)

ValidateAccess parses and validates an access token, returning its claims.

func (*LocalPaseto) ValidateRefresh

func (p *LocalPaseto) ValidateRefresh(token string) (LocalClaims, error)

ValidateRefresh parses and validates a refresh token, returning its claims.

type LocalPasetoConfig

type LocalPasetoConfig struct {
	Issuer     string
	AccessKey  []byte
	RefreshKey []byte
	AccessTTL  time.Duration
	RefreshTTL time.Duration
}

LocalPasetoConfig holds configuration for PASETO v4 local token generation.

type LocalTokenType

type LocalTokenType string

LocalTokenType distinguishes access vs refresh tokens.

const (
	AccessToken  LocalTokenType = "access"
	RefreshToken LocalTokenType = "refresh"
)

type PublicClaims

type PublicClaims struct {
	Subject      string
	Audience     string
	Issuer       string
	JTI          string
	ExpiresAt    time.Time
	IssuedAt     time.Time
	NotBefore    time.Time
	TokenType    PublicTokenType
	CustomClaims map[string]any
}

PublicClaims captures the essential claims for public PASETO tokens.

type PublicPaseto

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

PublicPaseto generates and validates PASETO v4 public tokens for access/refresh.

func NewPublicPaseto

func NewPublicPaseto(cfg PublicPasetoConfig) (*PublicPaseto, error)

func (*PublicPaseto) Generate

func (p *PublicPaseto) Generate(subject, audience string, customClaims map[string]any) (PublicTokens, error)

Generate issues a new pair of access and refresh public tokens for the given subject and audience. customClaims is an optional map of additional claims to include in both tokens.

func (*PublicPaseto) ValidateAccess

func (p *PublicPaseto) ValidateAccess(token string) (PublicClaims, error)

ValidateAccess parses and validates an access public token, returning its claims.

func (*PublicPaseto) ValidateRefresh

func (p *PublicPaseto) ValidateRefresh(token string) (PublicClaims, error)

ValidateRefresh parses and validates a refresh public token, returning its claims.

type PublicPasetoConfig

type PublicPasetoConfig struct {
	Issuer            string
	AccessPrivateKey  []byte
	AccessPublicKey   []byte
	RefreshPrivateKey []byte
	RefreshPublicKey  []byte
	AccessTTL         time.Duration
	RefreshTTL        time.Duration
}

PublicPasetoConfig holds configuration for PASETO v4 public token generation.

type PublicTokenType

type PublicTokenType string

PublicTokenType distinguishes access vs refresh tokens for public PASETO.

const (
	PublicAccessToken  PublicTokenType = "access"
	PublicRefreshToken PublicTokenType = "refresh"
)

type PublicTokens

type PublicTokens struct {
	Access  string
	Refresh string
}

PublicTokens bundles generated access and refresh public tokens.

type Tokens

type Tokens struct {
	Access  string
	Refresh string
}

Tokens bundles generated access and refresh tokens.

Jump to

Keyboard shortcuts

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