claims

package module
v0.0.1-alpha.22 Latest Latest
Warning

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

Go to latest
Published: Oct 9, 2025 License: MIT Imports: 8 Imported by: 9

README

ci Dependabot Updates

Claims

A flexible and type-safe Go library for working with JWT claims and authenticated identities.

Features

  • Type-safe claim access - Convert claims to various Go types with validation
  • Immutable Principals - Thread-safe authenticated identity representation
  • JWT integration - Built-in support for HMAC-SHA256 and RSA-SHA256 signing/validation
  • Flexible claim building - Multiple patterns for constructing claim sets
  • Serialization support - JSON serialization for message passing and caching

Quick Start

go get github.com/fgrzl/claims
Basic Usage
package main

import (
    "fmt"
    "time"
    
    "github.com/fgrzl/claims"
    "github.com/fgrzl/claims/jwtkit"
)

func main() {
    // Create a claim set
    cs := claims.NewClaimsSet("user123").
        SetIssuer("myapp").
        SetEmail("user@example.com").
        SetRoles("admin", "user")
    
    // Create an immutable principal
    principal := claims.NewPrincipal(cs)
    
    // Access claims with type safety
    fmt.Println("Subject:", principal.Subject())         // "user123"
    fmt.Println("Email:", principal.Email())             // "user@example.com"  
    fmt.Println("Roles:", principal.Roles())             // ["admin", "user"]
    
    // Create and validate JWT tokens
    secret := []byte("my-secret-key")
    signer := &jwtkit.HMAC256Signer{Secret: secret}
    validator := &jwtkit.HMAC256Validator{Secret: secret}
    
    // Sign
    token, err := signer.CreateToken(principal, 1*time.Hour)
    if err != nil {
        panic(err)
    }
    
    // Validate  
    validatedPrincipal, err := validator.Validate(token)
    if err != nil {
        panic(err)
    }
    
    fmt.Println("Validated Subject:", validatedPrincipal.Subject())
}

Core Concepts

Claims

Individual pieces of information with type conversion support:

claim := claims.NewClaim("age", "25")
age, ok := claim.IntValue()        // 25, true
ageStr := claim.Value()           // "25"
ClaimSets

Collections of claims with fluent builder pattern:

cs := claims.NewClaimsSet("user123").
    SetIssuer("myapp").
    SetExpiration(time.Now().Add(time.Hour).Unix()).
    SetRoles("admin", "user").
    Set("department", "engineering")  // Custom claims
Principals

Immutable authenticated identities:

principal := claims.NewPrincipal(cs)

// Standard JWT claims
subject := principal.Subject()
roles := principal.Roles()

// Custom claims  
dept := principal.CustomClaimValue("department")

JWT Integration

HMAC-SHA256 (Symmetric)
secret := []byte("your-secret-key")

signer := &jwtkit.HMAC256Signer{Secret: secret}
validator := &jwtkit.HMAC256Validator{Secret: secret}

token, _ := signer.CreateToken(principal, 1*time.Hour)
validatedPrincipal, _ := validator.Validate(token)
RSA-SHA256 (Asymmetric)
privateKey, _ := jwtkit.LoadPrivateKey("private.pem")
publicKey, _ := jwtkit.LoadPublicKey("public.pem")

signer := &jwtkit.RSASigner{PrivateKey: privateKey}
validator := &jwtkit.RSAValidator{PublicKey: publicKey}

token, _ := signer.CreateToken(principal, 1*time.Hour)
validatedPrincipal, _ := validator.Validate(token)

Advanced Features

Type Conversions
claim := claims.NewClaim("count", "42")

// Safe type conversions with validation
intVal, ok := claim.IntValue()      // 42, true
floatVal, ok := claim.Float64Value() // 42.0, true
boolVal, ok := claim.BoolValue()    // false, false

// Array handling
rolesClaim := claims.NewClaim("roles", "admin,user,guest")
roles := rolesClaim.Values(",")     // ["admin", "user", "guest"]
Principal Serialization
// For message passing or caching
jsonStr, err := claims.SerializePrincipal(principal)
reconstructed, err := claims.DeserializePrincipal(jsonStr)
Incremental Building
// Using ClaimList for dynamic construction
list := claims.NewClaimsList("sub", "user123")

if userEmail != "" {
    list = list.Add("email", userEmail)
}

cs := claims.ToClaimSet(list)
principal := claims.NewPrincipal(cs)

Documentation

Examples

Web Authentication
func authenticateHandler(w http.ResponseWriter, r *http.Request) {
    // Extract token from Authorization header
    authHeader := r.Header.Get("Authorization")
    token := strings.TrimPrefix(authHeader, "Bearer ")
    
    // Validate token
    principal, err := validator.Validate(token)
    if err != nil {
        http.Error(w, "Invalid token", http.StatusUnauthorized)
        return
    }
    
    // Check permissions
    if !hasRole(principal, "admin") {
        http.Error(w, "Insufficient permissions", http.StatusForbidden)
        return  
    }
    
    // Continue with authenticated request...
}

func hasRole(principal claims.Principal, requiredRole string) bool {
    for _, role := range principal.Roles() {
        if role == requiredRole {
            return true
        }
    }
    return false
}
Microservice Communication
// Service A: Create principal and serialize for message
principal := claims.NewPrincipal(
    claims.NewClaimsSet("user123").
        SetEmail("user@example.com").
        SetRoles("user", "admin"),
)

principalJSON, _ := claims.SerializePrincipal(principal)

// Send in message header
message := Message{
    Headers: map[string]string{
        "X-Principal": principalJSON,
    },
    Body: requestData,
}

// Service B: Deserialize principal from message  
principalJSON := message.Headers["X-Principal"]
principal, _ := claims.DeserializePrincipal(principalJSON)

// Use principal for authorization
if principal.CustomClaimValue("tenant_id") != allowedTenant {
    return errors.New("unauthorized tenant")
}

Requirements

  • Go 1.24.0 or later
  • Dependencies managed via Go modules

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Add tests for new functionality
  4. Ensure all tests pass: go test ./...
  5. Submit a pull request

License

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

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func SerializePrincipal

func SerializePrincipal(p Principal) (string, error)

SerializePrincipal serializes a Principal to JSON string.

func WithUser

func WithUser(ctx context.Context, user Principal) context.Context

Types

type Claim

type Claim interface {
	// Returns the name of the claim (e.g., "sub", "iss", "aud").
	Name() string

	// Returns the value of the claim as an string.
	Value() string

	// Returns the values of the claim as an []string.
	Values(sep string) []string

	// Returns the value of the claim as an int, if applicable.
	IntValue() (int, bool)

	// Returns the value of the claim as an int32, if applicable.
	Int32Value() (int32, bool)

	// Returns the value of the claim as an int64, if applicable.
	Int64Value() (int64, bool)

	// Returns the value of the claim as an float64, if applicable.
	Float64Value() (float64, bool)

	// Returns the value of the claim as a bool, if applicable.
	BoolValue() (bool, bool)

	// Returns the value of the claim as a bool, if applicable.
	UUIDValue() (uuid.UUID, bool)
}

Claim represents a single claim in a JWT token or claim set. It provides methods to access the claim's name and value in various formats.

func NewClaim

func NewClaim(name, value string) Claim

NewClaim creates a new Claim with the specified name and value.

type ClaimList

type ClaimList []Claim

ClaimList represents a slice of claims that can be built incrementally and converted to a ClaimSet.

func NewClaimsList

func NewClaimsList(key, value string) ClaimList

NewClaimsList creates a new ClaimList with the initial key-value pair.

func (ClaimList) Add

func (cl ClaimList) Add(key, value string) ClaimList

Add appends a new claim with the specified key and value to the ClaimList.

type ClaimSet

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

ClaimSet represents a collection of claims stored as key-value pairs. It provides methods to set, get, and access claims in various formats.

func MakeClaimsSet

func MakeClaimsSet(len int) *ClaimSet

MakeClaimsSet creates a new ClaimSet with the specified initial capacity.

func NewClaimsSet

func NewClaimsSet(subject string) *ClaimSet

NewClaimsSet creates a new ClaimSet with a subject claim.

func ToClaimSet

func ToClaimSet(cl ClaimList) *ClaimSet

ToClaimSet converts a ClaimList to a ClaimSet for more efficient claim access.

func (*ClaimSet) AppendRoles

func (cs *ClaimSet) AppendRoles(values ...string) *ClaimSet

AppendRoles appends new roles to existing roles and returns the ClaimSet for chaining.

func (*ClaimSet) AppendScopes

func (cs *ClaimSet) AppendScopes(values ...string) *ClaimSet

AppendScopes appends new scopes to existing scopes and returns the ClaimSet for chaining.

func (*ClaimSet) Audience

func (cs *ClaimSet) Audience() []string

Audience returns the audience claim as a slice of strings.

func (*ClaimSet) Claims

func (cs *ClaimSet) Claims() *ClaimSet

Claims returns a deep copy of the ClaimSet.

func (*ClaimSet) CustomClaim

func (cs *ClaimSet) CustomClaim(name string) Claim

CustomClaim returns a custom claim by name, or an empty claim if not found.

func (*ClaimSet) CustomClaimValue

func (cs *ClaimSet) CustomClaimValue(name string) string

CustomClaimValue returns the string value of a custom claim by name.

func (*ClaimSet) Email

func (cs *ClaimSet) Email() string

Email returns the email claim value.

func (*ClaimSet) ExpirationTime

func (cs *ClaimSet) ExpirationTime() int64

ExpirationTime returns the expiration time claim as a Unix timestamp.

func (*ClaimSet) Get

func (cs *ClaimSet) Get(key string) (Claim, bool)

Get returns a claim and a boolean indicating if it exists.

func (*ClaimSet) IssuedAt

func (cs *ClaimSet) IssuedAt() int64

IssuedAt returns the issued at claim as a Unix timestamp.

func (*ClaimSet) Issuer

func (cs *ClaimSet) Issuer() string

Issuer returns the issuer claim value.

func (*ClaimSet) JWTI

func (cs *ClaimSet) JWTI() string

JWTI returns the JWT ID claim value.

func (*ClaimSet) NotBefore

func (cs *ClaimSet) NotBefore() int64

NotBefore returns the not before claim as a Unix timestamp.

func (*ClaimSet) Range

func (cs *ClaimSet) Range(fn func(key string, claim Claim))

Range calls the provided function for each claim in the ClaimSet.

func (*ClaimSet) Roles

func (cs *ClaimSet) Roles() []string

Roles returns the roles claim as a slice of strings.

func (*ClaimSet) Scopes

func (cs *ClaimSet) Scopes() []string

Scopes returns the scopes claim as a slice of strings.

func (*ClaimSet) Set

func (cs *ClaimSet) Set(key, value string) *ClaimSet

Set adds or updates a claim with the specified key and value. Returns the same ClaimSet instance for method chaining.

func (*ClaimSet) SetAudience

func (cs *ClaimSet) SetAudience(v string) *ClaimSet

SetAudience sets the audience claim and returns the ClaimSet for chaining.

func (*ClaimSet) SetEmail

func (cs *ClaimSet) SetEmail(v string) *ClaimSet

SetEmail sets the email claim and returns the ClaimSet for chaining.

func (*ClaimSet) SetExpiration

func (cs *ClaimSet) SetExpiration(v int64) *ClaimSet

SetExpiration sets the expiration time claim and returns the ClaimSet for chaining.

func (*ClaimSet) SetIssuedAt

func (cs *ClaimSet) SetIssuedAt(v int64) *ClaimSet

SetIssuedAt sets the issued at claim and returns the ClaimSet for chaining.

func (*ClaimSet) SetIssuer

func (cs *ClaimSet) SetIssuer(v string) *ClaimSet

SetIssuer sets the issuer claim and returns the ClaimSet for chaining.

func (*ClaimSet) SetName

func (cs *ClaimSet) SetName(v string) *ClaimSet

SetName sets the name claim and returns the ClaimSet for chaining.

func (*ClaimSet) SetNotBefore

func (cs *ClaimSet) SetNotBefore(v int64) *ClaimSet

SetNotBefore sets the not before claim and returns the ClaimSet for chaining.

func (*ClaimSet) SetRoles

func (cs *ClaimSet) SetRoles(values ...string) *ClaimSet

SetRoles sets the roles claim with the provided values and returns the ClaimSet for chaining.

func (*ClaimSet) SetScopes

func (cs *ClaimSet) SetScopes(values ...string) *ClaimSet

SetScopes sets the scopes claim with the provided values and returns the ClaimSet for chaining.

func (*ClaimSet) SetSubject

func (cs *ClaimSet) SetSubject(v string) *ClaimSet

SetSubject sets the subject claim and returns the ClaimSet for chaining.

func (*ClaimSet) SetTokenID

func (cs *ClaimSet) SetTokenID(v string) *ClaimSet

SetTokenID sets the JWT ID claim and returns the ClaimSet for chaining.

func (*ClaimSet) Subject

func (cs *ClaimSet) Subject() string

Subject returns the subject claim value.

func (*ClaimSet) ToClaimList

func (cs *ClaimSet) ToClaimList() ClaimList

ToClaimList converts the ClaimSet to a ClaimList.

func (*ClaimSet) Username

func (cs *ClaimSet) Username() string

Username returns the username claim value.

func (*ClaimSet) Value

func (cs *ClaimSet) Value(key string) string

Value returns the string value of the claim with the specified key. Returns an empty string if the claim does not exist.

type Principal

type Principal interface {
	// Subject returns the unique identifier for the subject (e.g., user ID).
	Subject() string

	// Issuer returns the entity that issued the token.
	Issuer() string

	// Audience returns the intended audience(s) of the token.
	Audience() []string

	// ExpirationTime returns the token expiration time (Unix timestamp).
	ExpirationTime() int64

	// NotBefore returns the time before which the token is not valid (Unix timestamp).
	NotBefore() int64

	// IssuedAt returns the time at which the token was issued (Unix timestamp).
	IssuedAt() int64

	// JWTI returns the unique token ID.
	JWTI() string

	// Scopes returns the list of scopes or permissions granted.
	Scopes() []string

	// Roles returns the roles assigned to the subject.
	Roles() []string

	// Email returns the email address of the subject.
	Email() string

	// Username returns the human-readable name of the subject.
	Username() string

	// CustomClaim retrieves a custom claim by name.
	CustomClaim(name string) Claim

	// CustomClaimValue returns the string value of a custom claim.
	CustomClaimValue(name string) string

	// Claims returns a copy of the underlying claim set.
	Claims() *ClaimSet
}

Principal represents an authenticated identity with associated claims.

func DeserializePrincipal

func DeserializePrincipal(jsonStr string) (Principal, error)

DeserializePrincipal deserializes a JSON string to a Principal.

func NewPrincipal

func NewPrincipal(claimSet *ClaimSet) Principal

NewPrincipal constructs a Principal from a ClaimSet.

func NewPrincipalFromList

func NewPrincipalFromList(claimList ClaimList) Principal

NewPrincipalFromList constructs a Principal from a ClaimList.

func UserFromContext

func UserFromContext(ctx context.Context) (Principal, bool)

type ReconstructedPrincipal

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

ReconstructedPrincipal implements Principal from deserialized data.

func NewReconstructedPrincipal

func NewReconstructedPrincipal(fields SerializablePrincipal) *ReconstructedPrincipal

NewReconstructedPrincipal creates a new ReconstructedPrincipal from SerializablePrincipal.

func (*ReconstructedPrincipal) Audience

func (r *ReconstructedPrincipal) Audience() []string

Audience implements Principal

func (*ReconstructedPrincipal) Claims

func (r *ReconstructedPrincipal) Claims() *ClaimSet

Claims implements Principal (returns nil for reconstructed principals)

func (*ReconstructedPrincipal) CustomClaim

func (r *ReconstructedPrincipal) CustomClaim(name string) Claim

CustomClaim implements Principal (returns nil for reconstructed principals)

func (*ReconstructedPrincipal) CustomClaimValue

func (r *ReconstructedPrincipal) CustomClaimValue(name string) string

CustomClaimValue implements Principal (returns empty string for reconstructed principals)

func (*ReconstructedPrincipal) Email

func (r *ReconstructedPrincipal) Email() string

Email implements Principal

func (*ReconstructedPrincipal) ExpirationTime

func (r *ReconstructedPrincipal) ExpirationTime() int64

ExpirationTime implements Principal

func (*ReconstructedPrincipal) IssuedAt

func (r *ReconstructedPrincipal) IssuedAt() int64

IssuedAt implements Principal

func (*ReconstructedPrincipal) Issuer

func (r *ReconstructedPrincipal) Issuer() string

Issuer implements Principal

func (*ReconstructedPrincipal) JWTI

func (r *ReconstructedPrincipal) JWTI() string

JWTI implements Principal

func (*ReconstructedPrincipal) NotBefore

func (r *ReconstructedPrincipal) NotBefore() int64

NotBefore implements Principal

func (*ReconstructedPrincipal) Roles

func (r *ReconstructedPrincipal) Roles() []string

Roles implements Principal

func (*ReconstructedPrincipal) Scopes

func (r *ReconstructedPrincipal) Scopes() []string

Scopes implements Principal

func (*ReconstructedPrincipal) Subject

func (r *ReconstructedPrincipal) Subject() string

Subject implements Principal

func (*ReconstructedPrincipal) Username

func (r *ReconstructedPrincipal) Username() string

Username implements Principal

type SerializablePrincipal

type SerializablePrincipal struct {
	Subject        string   `json:"subject"`
	Issuer         string   `json:"issuer"`
	Audience       []string `json:"audience"`
	Scopes         []string `json:"scopes"`
	Roles          []string `json:"roles"`
	Email          string   `json:"email"`
	Username       string   `json:"username"`
	ExpirationTime int64    `json:"exp"`
	NotBefore      int64    `json:"nbf"`
	IssuedAt       int64    `json:"iat"`
	JWTI           string   `json:"jti"`
}

SerializablePrincipal represents the serializable fields of a Principal. This is used for serializing user principal data in message headers.

func DeserializePrincipalFields

func DeserializePrincipalFields(jsonStr string) (*SerializablePrincipal, error)

DeserializePrincipalFields deserializes a JSON string to SerializablePrincipal.

func ToSerializablePrincipal

func ToSerializablePrincipal(p Principal) SerializablePrincipal

ToSerializablePrincipal converts a Principal to a SerializablePrincipal.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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