Custom Claims
The built-in Claims struct covers common scenarios, but business systems often need additional fields. Implement the CustomClaims interface to define your own Claims struct.
CustomClaims Interface
type CustomClaims interface {
GetRegisteredClaims() *RegisteredClaims
Validate() error
}Only two methods to implement:
| Method | Description |
|---|---|
GetRegisteredClaims() | Returns standard JWT fields (iss, sub, aud, etc.) |
Validate() | Custom validation logic |
Defining Custom Claims
type MyClaims struct {
UserID string `json:"user_id"`
Email string `json:"email"`
Role string `json:"role"`
jwt.RegisteredClaims
}
func (c *MyClaims) GetRegisteredClaims() *jwt.RegisteredClaims {
return &c.RegisteredClaims
}
func (c *MyClaims) Validate() error {
if c.UserID == "" {
return errors.New("user_id is required")
}
if c.Email == "" {
return errors.New("email is required")
}
return nil
}Key Points
- Must embed
jwt.RegisteredClaims GetRegisteredClaims()returns a pointer to the embedded fieldValidate()is called during both token creation and validation
Using Custom Claims
Create Token
claims := &MyClaims{
UserID: "user123",
Email: "[email protected]",
Role: "admin",
}
token, err := processor.Create(claims)Validate into Custom Struct
Use ValidateInto to parse the token into a custom struct:
myClaims := &MyClaims{}
result, valid, err := processor.ValidateInto(token, myClaims)
if err != nil {
panic(err)
}
if valid {
parsed := result.(*MyClaims)
fmt.Println("UserID:", parsed.UserID)
fmt.Println("Email:", parsed.Email)
}Refresh into Custom Struct
Use RefreshInto to refresh a token while preserving custom fields:
newToken, err := processor.RefreshInto(refreshToken, &MyClaims{})
if err != nil {
panic(err)
}Timing Field Protection
RefreshInto automatically restores Claims timing fields (IssuedAt, ExpiresAt, ID), even if the operation fails.
Validation Differences
Built-in *Claims and custom types follow different validation paths:
| Validation | *Claims | Custom Types |
|---|---|---|
Validate() method | ✅ | ✅ |
| String length limit (256 chars) | ✅ | ❌ |
| Array size limit (100 items) | ✅ | ❌ |
| Injection pattern detection | ✅ | ❌ |
| Control character filtering | ✅ | ❌ |
Extra field restrictions | ✅ | N/A |
| Registered claims sanitization | ✅ | ✅ |
Important
Custom Claims business fields are not deep-validated. Please implement all necessary checks in the Validate() method.
Optional Interface: RateLimitKeyer
Custom Claims can implement the RateLimitKeyer interface to provide a rate limit key:
func (c *MyClaims) RateLimitKey() string {
return c.Email // Use Email as rate limit key
}Rate limit key lookup priority: Subject → *Claims.UserID → RateLimitKey().
Next Steps
- API Reference → Interfaces — CustomClaims full definition
- API Reference → Processor — ValidateInto / RefreshInto methods
- Advanced Examples — Custom Claims complete example