Core Concepts
This page explains the core abstractions and design model behind CyberGo JWT, helping you build a mental model before diving into code. To start coding right away, jump to Quick Start.
Processor — The Central Type
Processor is the central type of the library, created via jwt.New(cfg). It encapsulates the full logic for token creation, validation, refresh, and revocation. All methods are goroutine-safe — a single instance can be shared across goroutines.
Call Close() when done to securely wipe the secret key and release pooled resources:
<!-- check-code: skip -->
cfg := jwt.DefaultConfig()
cfg.SecretKey = "your-32-byte-secret-key-here-minimum"
processor, err := jwt.New(cfg)
if err != nil {
log.Fatal(err)
}
defer processor.Close()Processor implements the TokenManager interface, enabling dependency injection and test substitution.
Token Lifecycle
A token moves through the following stages from issuance to invalidation:
Issue Create(claims) → Access token (short-lived)
CreateRefresh(claims) → Refresh token (long-lived)
Verify Validate(token) → Claims (checks signature, expiry, issuer, blacklist)
Refresh Refresh(refreshToken) → New access token
Revoke Revoke(token) → Added to blacklist
Check IsRevoked(token) → boolEach stage returns sentinel errors (e.g. ErrTokenExpired, ErrTokenRevoked) that can be matched precisely with errors.Is(). See Error Handling.
Dual-Layer Token Model
CyberGo JWT uses an access token + refresh token design:
| Access Token | Refresh Token | |
|---|---|---|
| Purpose | API authentication | Obtain new access tokens |
| Default TTL | 15 minutes | 7 days |
| Issue method | Create | CreateRefresh |
| Refresh method | — | Refresh |
Why two layers? Access tokens are short-lived, so the risk window is small even if leaked. Refresh tokens are long-lived but only used to obtain new access tokens, never for direct API authentication. This design balances security with user experience — users don't need to log in frequently, and access tokens can be refreshed silently after expiry.
Rotation semantics
Refresh does not automatically revoke the refresh token. The original refresh token remains valid until it expires or is explicitly Revoked. For one-time-use semantics (refresh token rotation), call Revoke on the old refresh token after a successful Refresh. See Token Refresh & Rotation.
Claims Structure
Claims carry the user identity data inside a token. CyberGo JWT provides a two-layer structure:
RegisteredClaims (RFC 7519 standard claims, auto-filled and validated):
| Field | claim | Description |
|---|---|---|
| Issuer | iss | Issuer identifier |
| Subject | sub | Subject identifier (also used as rate-limit key) |
| Audience | aud | Intended audience |
| ExpiresAt | exp | Expiration time |
| NotBefore | nbf | Not-before time |
| IssuedAt | iat | Issuance time |
| ID | jti | Unique ID (blacklist key) |
| TokenType | token_type | access or refresh |
Claims (built-in business claims, embeds RegisteredClaims):
<!-- check-code: skip -->
type Claims struct {
UserID string // User ID
Username string // Username
Role string // Role
Permissions []string // Permission list
Scopes []string // OAuth scopes
SessionID string // Session ID
ClientID string // Client ID
Extra map[string]any // Extra fields
RegisteredClaims // Standard claims (embedded)
}All fields undergo input validation: string length cap of 256, array cap of 100, injection pattern detection (XSS/SQLi signatures).
CustomClaims Interface
When the built-in Claims don't meet your needs, implement the CustomClaims interface to define your own claim structure:
<!-- check-code: skip -->
type AppClaims struct {
UserID string `json:"user_id"`
TeamID string `json:"team_id"`
Roles []string `json:"roles,omitempty"`
jwt.RegisteredClaims
}
func (c *AppClaims) GetRegisteredClaims() *jwt.RegisteredClaims {
return &c.RegisteredClaims
}
func (c *AppClaims) Validate() error {
if c.UserID == "" {
return errors.New("user_id is required")
}
return nil
}Custom types are validated with ValidateInto and refreshed with RefreshInto — the Processor parses the token and populates your struct. See Custom Claims.
Config Overview
Config is the unified configuration entry point for Processor. Start with DefaultConfig() for sensible defaults, then set your signing key:
| Group | Fields | Description |
|---|---|---|
| Signing | SecretKey / SigningKey / VerificationKey / SigningMethod | HMAC uses SecretKey; RSA/ECDSA uses SigningKey |
| Token | AccessTokenTTL / RefreshTokenTTL | Access and refresh token lifetimes |
| Validation | Issuer / ExpectedAudience / RequireExpiration / ClockSkew | Issuer, audience, mandatory expiry, clock tolerance |
| Security | Blacklist / EnableRateLimit | Revocation store and rate limiting |
| Extension | Clock | Clock injection (for testing) |
For algorithm selection see Signing Algorithms; for full field documentation see Configuration.
Extension Interfaces
CyberGo JWT is extensible through interfaces:
| Interface | Purpose |
|---|---|
TokenManager | Core interface implemented by Processor. Define your own narrower subset (e.g. only Create + Validate) for dependency injection and decoupling |
BlacklistStore | Custom blacklist backend (e.g. Redis). Implement Add / Contains / Close to connect external storage |
RateLimitProvider | Custom rate limiter. Implement Allow / Reset / Close to replace the built-in token bucket |
ClockProvider | Clock injection. FixedClock returns a fixed time for deterministic control over expiry and refresh logic in tests |
Next Steps
- Quick Start — Issue your first token
- Signing Algorithms — HMAC, RSA, ECDSA selection guide
- Configuration — Full field reference and security hardening
- Web Server Integration — Auth middleware and RBAC in practice