Documentation
ΒΆ
Overview ΒΆ
Package zerojwt provides an ultra-fast, zero-allocation (0 B/op, 0 allocs/op) JWT validator and signer in pure Go supporting HS256, HS384, HS512, EdDSA (Ed25519), and ES256.
Index ΒΆ
- Constants
- Variables
- func AppendEscapedJSONString(dst, s []byte) []byte
- func NextArrayElement(b []byte) (val []byte, isStr bool, rest []byte, ok bool)
- func NextJSONProp(b []byte) (key, val []byte, isStr bool, rest []byte, ok bool)
- func ParseNumeric(b []byte) (float64, bool)
- func ParsePositiveInt(val []byte) (int64, bool)
- func TrimJSONArray(b []byte) ([]byte, bool)
- func TrimJSONObject(b []byte) ([]byte, bool)
- func UnescapeJSONInPlace(s []byte) []byte
- type Algorithm
- type Claims
- type ClaimsLarge
- type Key
- type Options
- type Scratch
- type SignBuilder
- func (b *SignBuilder) SetAudience(aud []byte) *SignBuilder
- func (b *SignBuilder) SetClaimBool(key string, val bool) *SignBuilder
- func (b *SignBuilder) SetClaimBytes(key string, val []byte) *SignBuilder
- func (b *SignBuilder) SetClaimInt(key string, val int64) *SignBuilder
- func (b *SignBuilder) SetClaimRawJSON(key string, rawJSON []byte) *SignBuilder
- func (b *SignBuilder) SetClaimString(key, val string) *SignBuilder
- func (b *SignBuilder) SetExpiresAt(exp int64) *SignBuilder
- func (b *SignBuilder) SetIssuedAt(iat int64) *SignBuilder
- func (b *SignBuilder) SetIssuer(iss []byte) *SignBuilder
- func (b *SignBuilder) SetJTI(jti []byte) *SignBuilder
- func (b *SignBuilder) SetNotBefore(nbf int64) *SignBuilder
- func (b *SignBuilder) SetSubject(sub []byte) *SignBuilder
- func (b *SignBuilder) SetUsername(username []byte) *SignBuilder
- func (b *SignBuilder) Sign() ([]byte, error)
- type Verifier
- func (v *Verifier) Destroy()
- func (v *Verifier) Middleware(next http.Handler) http.Handler
- func (v *Verifier) NewScratch() *Scratch
- func (v *Verifier) NewSigner(dst []byte) SignBuilder
- func (v *Verifier) NewSignerWithScratch(dst []byte, st *Scratch) SignBuilder
- func (v *Verifier) ProtectFunc(next func(w http.ResponseWriter, r *http.Request, claims *Claims)) http.HandlerFunc
- func (v *Verifier) Sign(dst []byte, payloadJSON []byte) []byte
- func (v *Verifier) SignClaims(dst []byte, sub, username []byte, iat, exp int64) []byte
- func (v *Verifier) SignHS256(dst []byte, payloadJSON []byte) []byte
- func (v *Verifier) SignHS256WithScratch(dst []byte, payloadJSON []byte, st *Scratch) []byte
- func (v *Verifier) SignWithScratch(dst []byte, payloadJSON []byte, st *Scratch) []byte
- func (v *Verifier) Verify(tok []byte, nowUnix int64, out *Claims) error
- func (v *Verifier) VerifyBearer(authHeader []byte, nowUnix int64, out *Claims) error
- func (v *Verifier) VerifyCustom(tok []byte, nowUnix int64, onClaim func(key, val []byte, isStr bool) bool) error
- func (v *Verifier) VerifyLarge(tok []byte, nowUnix int64, out *ClaimsLarge) error
- func (v *Verifier) VerifyLargeWithScratch(tok []byte, nowUnix int64, out *ClaimsLarge, st *Scratch) error
- func (v *Verifier) VerifyWithScratch(tok []byte, nowUnix int64, out *Claims, st *Scratch) error
Examples ΒΆ
Constants ΒΆ
const ( // MaxHeaderSize is the default maximum decoded byte length of a JWT header in zero-alloc mode. MaxHeaderSize = 128 // MaxPayloadSize is the default maximum decoded byte length of a JWT payload in zero-alloc mode. MaxPayloadSize = 1024 )
Variables ΒΆ
var ( // ErrMissingBearer is returned by VerifyBearer when the "Bearer " prefix is absent. ErrMissingBearer = errors.New("zerojwt: missing Bearer prefix") // ErrInvalidToken is returned when the token does not have 3 valid Base64URL segments. ErrInvalidToken = errors.New("zerojwt: malformed token structure") // ErrInvalidHeader is returned when the JWT header is not valid JSON or specifies an unsupported algorithm. ErrInvalidHeader = errors.New("zerojwt: invalid header or unsupported algorithm") // ErrInvalidSignature is returned when the cryptographic signature verification fails. ErrInvalidSignature = errors.New("zerojwt: signature verification failed") // ErrExpiredToken is returned when the current timestamp is >= the "exp" claim. ErrExpiredToken = errors.New("zerojwt: token is expired") // ErrNotValidYet is returned when the current timestamp is < the "nbf" claim. ErrNotValidYet = errors.New("zerojwt: token is not valid yet (nbf)") // ErrInvalidPayload is returned when the payload JSON is malformed or required claims are invalid. ErrInvalidPayload = errors.New("zerojwt: invalid token payload claims") // ErrPayloadTooLarge is returned when the decoded payload exceeds the configured MaxPayloadSize. ErrPayloadTooLarge = errors.New("zerojwt: payload exceeds maximum zero-alloc buffer size") // ErrInvalidIssuer is returned when the "iss" claim is missing or does not match ExpectedIssuer. ErrInvalidIssuer = errors.New("zerojwt: invalid or mismatched token issuer (iss)") // ErrInvalidAudience is returned when the "aud" claim is missing or does not match ExpectedAudience. ErrInvalidAudience = errors.New("zerojwt: invalid or mismatched token audience (aud)") // ErrUnknownKeyID is returned when the header specifies a "kid" that is not registered in the Verifier. ErrUnknownKeyID = errors.New("zerojwt: unknown key ID (kid) in header") )
Pre-allocated static errors returned by zerojwt. Comparing against these errors with errors.Is or == performs zero allocations.
Functions ΒΆ
func AppendEscapedJSONString ΒΆ
AppendEscapedJSONString appends a JSON-escaped string (with surrounding quotes) to dst using unrolled 8-byte vectorized span checks and bulk memory copies.
func NextArrayElement ΒΆ
NextArrayElement extracts the next element from a JSON array body (inside '[' and ']'). It operates strictly in-place on b with zero heap allocations (0 B/op, 0 allocs/op).
func NextJSONProp ΒΆ
NextJSONProp extracts the next top-level "key": value pair from a JSON object body (inside '{' and '}'). It operates strictly in-place on b with zero heap allocations (0 B/op, 0 allocs/op). If a string value contains escape sequences (e.g., \" or \u00e7), it unescapes the slice in-place.
func ParseNumeric ΒΆ
ParseNumeric parses a JSON number (integer or floating point, e.g. Unix timestamps) without allocations.
func ParsePositiveInt ΒΆ
ParsePositiveInt parses a strictly positive 64-bit integer from a byte slice of digits.
func TrimJSONArray ΒΆ
TrimJSONArray strips surrounding whitespace and outer '[' and ']' brackets from a JSON array.
func TrimJSONObject ΒΆ
TrimJSONObject strips surrounding whitespace and outer '{' and '}' braces from a JSON object.
func UnescapeJSONInPlace ΒΆ
UnescapeJSONInPlace unescapes JSON string escape sequences in-place without allocating memory.
Types ΒΆ
type Algorithm ΒΆ
type Algorithm string
Algorithm represents a supported JWS cryptographic algorithm (RFC 7518 / RFC 8037).
type Claims ΒΆ
type Claims struct {
SubjectID int64 // Parsed positive integer ID when "sub" is numeric (e.g. "123" -> 123)
IssuedAt int64 // "iat" claim (Unix seconds)
ExpiresAt int64 // "exp" claim (Unix seconds)
NotBefore int64 // "nbf" claim (Unix seconds)
HasSub bool // True if "sub" claim was present
HasUsername bool // True if "username" claim was present
HasIss bool // True if "iss" claim was present
HasAud bool // True if "aud" claim was present
HasJti bool // True if "jti" claim was present
HasExp bool // True if "exp" claim was present
HasNbf bool // True if "nbf" claim was present
// contains filtered or unexported fields
}
Claims holds standard JWT claims on the caller's stack without heap allocations. Its internal fixed buffers own the copied claim bytes, ensuring 100% safety against data races even after the internal Scratch buffer returns to the pool.
func ClaimsFromContext ΒΆ
ClaimsFromContext retrieves the verified *Claims from a request context populated by Verifier.Middleware.
func (*Claims) Audience ΒΆ
Audience returns the primary "aud" claim as a byte slice backed by Claims' inline buffer.
func (*Claims) Clear ΒΆ
func (c *Claims) Clear()
Clear resets all fields and explicitly zeroes all internal claim buffers with 0x00 (memclr).
func (*Claims) Issuer ΒΆ
Issuer returns the "iss" claim as a byte slice backed by Claims' inline buffer.
func (*Claims) JTI ΒΆ
JTI returns the "jti" (JWT ID) claim as a byte slice backed by Claims' inline buffer.
func (*Claims) Reset ΒΆ
func (c *Claims) Reset()
Reset resets length markers and flags for fast reuse without zeroing the underlying byte arrays.
type ClaimsLarge ΒΆ
type ClaimsLarge struct {
SubjectID int64
IssuedAt int64
ExpiresAt int64
NotBefore int64
HasSub bool
HasUsername bool
HasIss bool
HasAud bool
HasJti bool
HasExp bool
HasNbf bool
// contains filtered or unexported fields
}
ClaimsLarge provides expanded 256-byte inline buffers for deployments where Subject, Username, Issuer, Audience, or JTI identifiers exceed 64/128 bytes.
func (*ClaimsLarge) Audience ΒΆ
func (c *ClaimsLarge) Audience() []byte
func (*ClaimsLarge) Clear ΒΆ
func (c *ClaimsLarge) Clear()
func (*ClaimsLarge) Issuer ΒΆ
func (c *ClaimsLarge) Issuer() []byte
func (*ClaimsLarge) JTI ΒΆ
func (c *ClaimsLarge) JTI() []byte
func (*ClaimsLarge) Reset ΒΆ
func (c *ClaimsLarge) Reset()
func (*ClaimsLarge) Subject ΒΆ
func (c *ClaimsLarge) Subject() []byte
func (*ClaimsLarge) Username ΒΆ
func (c *ClaimsLarge) Username() []byte
type Key ΒΆ
type Key struct {
ID string
Secret []byte
Ed25519Public ed25519.PublicKey
ECDSAPublic *ecdsa.PublicKey
}
Key represents a named cryptographic key for "kid" (Key ID) rotation in JWT headers.
type Options ΒΆ
type Options struct {
// Algorithm selects the JWS algorithm (default: AlgHS256).
Algorithm Algorithm
// MaxHeaderSize sets the maximum decoded byte length of a JWT header (default: 128).
MaxHeaderSize int
// MaxPayloadSize sets the maximum decoded byte length of a JWT payload (default: 1024).
MaxPayloadSize int
// Leeway defines the clock skew tolerance for "exp" and "nbf" validation.
Leeway time.Duration
// ExpectedIssuer enforces that the token's "iss" claim matches this value.
ExpectedIssuer string
// ExpectedAudience enforces that the token's "aud" claim (string or array) contains this value.
ExpectedAudience string
// Keys registers named keys for automatic "kid" header lookup during verification.
Keys []Key
// ActiveKeyID embeds `"kid":"<ActiveKeyID>"` in the JWT header when signing tokens.
ActiveKeyID string
// Ed25519PublicKey is the 32-byte public key used when Algorithm is AlgEdDSA.
Ed25519PublicKey ed25519.PublicKey
// Ed25519PrivateKey is the 64-byte private key used for signing when Algorithm is AlgEdDSA.
Ed25519PrivateKey ed25519.PrivateKey
// ECDSAPublicKey is the P-256 public key used when Algorithm is AlgES256.
ECDSAPublicKey *ecdsa.PublicKey
// ECDSAPrivateKey is the P-256 private key used for signing when Algorithm is AlgES256.
ECDSAPrivateKey *ecdsa.PrivateKey
// ZeroMemory zeroes out sensitive scratch buffers with 0x00 (memclr) after each operation.
ZeroMemory bool
}
Options configures algorithm, buffer dimensions, RFC 7519 validation rules, key rotation ("kid"), and FIPS/PCI-DSS memory sanitization for a Verifier.
type Scratch ΒΆ
type Scratch struct {
// contains filtered or unexported fields
}
Scratch holds reusable buffers and pre-initialized HMAC hashers. In multi-goroutine servers, Verifier manages a sync.Pool of Scratch instances automatically. In single-threaded event loops (such as gnet with LockOSThread), callers can hold a single Scratch instance and call VerifyWithScratch to bypass even sync.Pool overhead.
type SignBuilder ΒΆ
type SignBuilder struct {
// contains filtered or unexported fields
}
SignBuilder is a stack-allocated, zero-allocation fluent builder for constructing and signing JWT tokens with arbitrary custom claims.
func (*SignBuilder) SetAudience ΒΆ
func (b *SignBuilder) SetAudience(aud []byte) *SignBuilder
SetAudience appends the standard "aud" claim.
func (*SignBuilder) SetClaimBool ΒΆ
func (b *SignBuilder) SetClaimBool(key string, val bool) *SignBuilder
SetClaimBool appends a custom boolean claim.
func (*SignBuilder) SetClaimBytes ΒΆ
func (b *SignBuilder) SetClaimBytes(key string, val []byte) *SignBuilder
SetClaimBytes appends a custom string claim from a byte slice with JSON escaping.
func (*SignBuilder) SetClaimInt ΒΆ
func (b *SignBuilder) SetClaimInt(key string, val int64) *SignBuilder
SetClaimInt appends a custom 64-bit integer claim.
func (*SignBuilder) SetClaimRawJSON ΒΆ
func (b *SignBuilder) SetClaimRawJSON(key string, rawJSON []byte) *SignBuilder
SetClaimRawJSON appends a pre-formatted JSON value (such as an array `["admin","editor"]` or object).
func (*SignBuilder) SetClaimString ΒΆ
func (b *SignBuilder) SetClaimString(key, val string) *SignBuilder
SetClaimString appends a custom string claim with JSON escaping.
func (*SignBuilder) SetExpiresAt ΒΆ
func (b *SignBuilder) SetExpiresAt(exp int64) *SignBuilder
SetExpiresAt appends the standard "exp" claim (Unix seconds).
func (*SignBuilder) SetIssuedAt ΒΆ
func (b *SignBuilder) SetIssuedAt(iat int64) *SignBuilder
SetIssuedAt appends the standard "iat" claim (Unix seconds).
func (*SignBuilder) SetIssuer ΒΆ
func (b *SignBuilder) SetIssuer(iss []byte) *SignBuilder
SetIssuer appends the standard "iss" claim.
func (*SignBuilder) SetJTI ΒΆ
func (b *SignBuilder) SetJTI(jti []byte) *SignBuilder
SetJTI appends the standard "jti" (JWT ID) claim.
func (*SignBuilder) SetNotBefore ΒΆ
func (b *SignBuilder) SetNotBefore(nbf int64) *SignBuilder
SetNotBefore appends the standard "nbf" claim (Unix seconds).
func (*SignBuilder) SetSubject ΒΆ
func (b *SignBuilder) SetSubject(sub []byte) *SignBuilder
SetSubject appends the standard "sub" claim.
func (*SignBuilder) SetUsername ΒΆ
func (b *SignBuilder) SetUsername(username []byte) *SignBuilder
SetUsername appends the "username" claim.
func (*SignBuilder) Sign ΒΆ
func (b *SignBuilder) Sign() ([]byte, error)
Sign finalizes the JSON payload, signs the token into dst, and returns the resulting slice. If the SignBuilder was created via NewSigner, the internal Scratch is returned to the pool.
type Verifier ΒΆ
type Verifier struct {
// contains filtered or unexported fields
}
Verifier validates and signs JWT tokens with zero heap allocations (0 B/op, 0 allocs/op). A Verifier is 100% safe for concurrent use by multiple goroutines.
func NewES256Verifier ΒΆ
NewES256Verifier creates a new concurrent-safe ECDSA P-256 (ES256) Verifier. For verification-only nodes, priv can be nil.
func NewEd25519Verifier ΒΆ
NewEd25519Verifier creates a new concurrent-safe EdDSA (Ed25519) Verifier. For verification-only nodes, priv can be nil.
Example ΒΆ
ExampleNewEd25519Verifier demonstrates an asymmetric microservices architecture where the authentication authority signs with an Ed25519 private key, and consuming microservices verify tokens using only the 32-byte public key (privKey = nil).
package main
import (
"crypto/ed25519"
"fmt"
"github.com/KaikeGM/zerojwt"
)
func main() {
// In production, keys are loaded from secure config/vault.
// We generate an Ed25519 keypair for demonstration:
pubKey, privKey, err := ed25519.GenerateKey(nil)
if err != nil {
fmt.Printf("Key generation error: %v\n", err)
return
}
now := int64(1700000000)
// 1. Authentication Server: initialized with both pubKey and privKey to sign tokens.
authServer := zerojwt.NewEd25519Verifier(pubKey, privKey, zerojwt.Options{
ExpectedIssuer: "auth.internal",
})
var tokBuf [512]byte
token := authServer.SignClaims(tokBuf[:0], []byte("srv_99"), []byte("payment-worker"), now, now+1800)
// 2. Client Microservice: initialized with public key ONLY (privKey is nil).
// This ensures the microservice can verify tokens, but cannot forge or issue them.
microserviceVerifier := zerojwt.NewEd25519Verifier(pubKey, nil, zerojwt.Options{
ExpectedIssuer: "auth.internal",
})
var claims zerojwt.Claims
if err := microserviceVerifier.Verify(token, now, &claims); err != nil {
fmt.Printf("Microservice verification failed: %v\n", err)
return
}
fmt.Printf("Microservice verified token for %s (issuer valid: %t)\n", claims.Username(), claims.HasIss)
}
Output: Microservice verified token for payment-worker (issuer valid: true)
func NewVerifier ΒΆ
NewVerifier creates a new concurrent-safe HS256 Verifier for the given secret key using the default buffer limits (128B header, 1024B payload).
func NewVerifierWithOptions ΒΆ
NewVerifierWithOptions creates a new concurrent-safe Verifier with custom algorithm, buffer dimensions, clock skew leeway, issuer/audience rules, and key rotation.
func (*Verifier) Destroy ΒΆ
func (v *Verifier) Destroy()
Destroy zeroes out all cryptographic secret keys stored inside the Verifier.
func (*Verifier) Middleware ΒΆ
Middleware provides a standard net/http and chi compatible middleware that validates the Authorization: Bearer <token> header and attaches *Claims to the request's context.Context.
func (*Verifier) NewScratch ΒΆ
NewScratch allocates a new Scratch state bound to this Verifier's keys and buffer sizes. Useful for single-threaded event-loop servers (e.g. gnet) using VerifyWithScratch.
func (*Verifier) NewSigner ΒΆ
func (v *Verifier) NewSigner(dst []byte) SignBuilder
NewSigner creates a fluent SignBuilder backed by the Verifier's Scratch pool. Calling Sign() automatically releases the internal Scratch back to the pool.
Example ΒΆ
ExampleVerifier_NewSigner demonstrates using the fluent SignBuilder to compose and sign a JWT with custom claims entirely on the stack with 0 heap allocations.
package main
import (
"fmt"
"github.com/KaikeGM/zerojwt"
)
func main() {
secret := []byte("super-secret-key-32-bytes-long!!")
verifier := zerojwt.NewVerifier(secret)
now := int64(1700000000)
var tokBuf [512]byte
b := verifier.NewSigner(tokBuf[:0])
b.SetSubject([]byte("user_456")).
SetUsername([]byte("bob")).
SetIssuer([]byte("auth.service")).
SetAudience([]byte("api.service")).
SetClaimString("role", "admin").
SetClaimInt("tenant_id", 42).
SetClaimBool("mfa", true).
SetExpiresAt(now + 3600)
token, err := b.Sign()
if err != nil {
fmt.Printf("Sign error: %v\n", err)
return
}
var claims zerojwt.Claims
if err := verifier.Verify(token, now, &claims); err != nil {
fmt.Printf("Verify error: %v\n", err)
return
}
fmt.Printf("Subject: %s\n", claims.Subject())
fmt.Printf("Username: %s\n", claims.Username())
fmt.Printf("HasExp: %t\n", claims.HasExp)
}
Output: Subject: user_456 Username: bob HasExp: true
func (*Verifier) NewSignerWithScratch ΒΆ
func (v *Verifier) NewSignerWithScratch(dst []byte, st *Scratch) SignBuilder
NewSignerWithScratch creates a fluent SignBuilder using a caller-supplied Scratch (ideal for single-threaded event loops like gnet).
func (*Verifier) ProtectFunc ΒΆ
func (v *Verifier) ProtectFunc(next func(w http.ResponseWriter, r *http.Request, claims *Claims)) http.HandlerFunc
ProtectFunc wraps a handler that receives stack-allocated *Claims directly, achieving 0 B/op and 0 allocs/op per authenticated HTTP request.
Example ΒΆ
ExampleVerifier_ProtectFunc demonstrates wrapping an HTTP handler with ultra-low latency and 0 heap allocations per authenticated request.
package main
import (
"fmt"
"net/http"
"net/http/httptest"
"time"
"github.com/KaikeGM/zerojwt"
)
func main() {
secret := []byte("super-secret-key-32-bytes-long!!")
verifier := zerojwt.NewVerifier(secret)
now := time.Now().Unix()
// Create an authenticated HTTP handler receiving stack-allocated *Claims
handler := verifier.ProtectFunc(func(w http.ResponseWriter, r *http.Request, claims *zerojwt.Claims) {
fmt.Fprintf(w, "Hello, %s!", claims.Username())
})
// Sign a test token
var tokBuf [512]byte
token := verifier.SignClaims(tokBuf[:0], []byte("u1"), []byte("charlie"), now, now+3600)
// Simulate an HTTP request with the Bearer token
req := httptest.NewRequest("GET", "/profile", nil)
req.Header.Set("Authorization", "Bearer "+string(token))
rec := httptest.NewRecorder()
handler.ServeHTTP(rec, req)
fmt.Printf("Status: %d, Body: %s\n", rec.Code, rec.Body.String())
}
Output: Status: 200, Body: Hello, charlie!
func (*Verifier) Sign ΒΆ
Sign signs a raw JSON payload with the Verifier's configured algorithm (HS256, HS384, HS512, EdDSA, ES256) and appends the complete JWT token ("header.payload.signature") to dst with zero heap allocations (when dst has sufficient capacity).
func (*Verifier) SignClaims ΒΆ
SignClaims formats a standard JSON payload `{"sub":"...","username":"...","iat":...,"exp":...}` into Scratch and appends the signed JWT token to dst with zero heap allocations.
func (*Verifier) SignHS256 ΒΆ
SignHS256 signs a raw JSON payload and appends the complete JWT token ("header.payload.signature") to dst with zero heap allocations (when dst has sufficient capacity).
func (*Verifier) SignHS256WithScratch ΒΆ
SignHS256WithScratch signs a raw JSON payload using a caller-supplied Scratch state.
func (*Verifier) SignWithScratch ΒΆ
SignWithScratch signs a raw JSON payload using a caller-supplied Scratch state.
func (*Verifier) Verify ΒΆ
Verify validates the token signature, checks temporal ("exp", "nbf") and structural ("iss", "aud") claims against nowUnix, and populates out with the parsed claims. Safe for concurrent use across goroutines; performs 0 heap allocations (0 B/op, 0 allocs/op).
Example ΒΆ
ExampleVerifier_Verify demonstrates token verification with zero heap allocations, extracting standard claims, and checking sentinel errors using errors.Is.
package main
import (
"errors"
"fmt"
"github.com/KaikeGM/zerojwt"
)
func main() {
secret := []byte("super-secret-key-32-bytes-long!!")
verifier := zerojwt.NewVerifier(secret)
now := int64(1700000000)
// Issue a valid token into a stack-allocated buffer (0 allocs/op)
var tokBuf [512]byte
token := verifier.SignClaims(tokBuf[:0], []byte("user_123"), []byte("alice"), now, now+3600)
// Verify token into stack-allocated Claims
var claims zerojwt.Claims
if err := verifier.Verify(token, now, &claims); err != nil {
switch {
case errors.Is(err, zerojwt.ErrExpiredToken):
fmt.Println("Token is expired")
case errors.Is(err, zerojwt.ErrInvalidSignature):
fmt.Println("Invalid signature")
default:
fmt.Printf("Validation error: %v\n", err)
}
return
}
fmt.Printf("Authenticated: %s (%s)\n", claims.Username(), claims.Subject())
// Verifying an expired token triggers ErrExpiredToken
err := verifier.Verify(token, now+7200, &claims)
if errors.Is(err, zerojwt.ErrExpiredToken) {
fmt.Println("Detected expired token successfully")
}
}
Output: Authenticated: alice (user_123) Detected expired token successfully
func (*Verifier) VerifyBearer ΒΆ
VerifyBearer strips the "Bearer " prefix from an HTTP Authorization header and verifies the token with zero heap allocations.
func (*Verifier) VerifyCustom ΒΆ
func (v *Verifier) VerifyCustom(tok []byte, nowUnix int64, onClaim func(key, val []byte, isStr bool) bool) error
VerifyCustom validates the token signature, checks "exp", "nbf", "iss", and "aud" against nowUnix, and invokes onClaim(key, val, isString) for every top-level JSON claim in the payload. Performs 0 heap allocations. Note: key and val slices are valid only during the onClaim callback.
Example ΒΆ
ExampleVerifier_VerifyCustom demonstrates inspecting arbitrary custom JSON attributes and claims directly from the verified payload buffer in 0 allocations.
package main
import (
"fmt"
"github.com/KaikeGM/zerojwt"
)
func main() {
secret := []byte("super-secret-key-32-bytes-long!!")
verifier := zerojwt.NewVerifier(secret)
now := int64(1700000000)
var tokBuf [512]byte
b := verifier.NewSigner(tokBuf[:0])
b.SetSubject([]byte("user_789")).
SetClaimString("department", "engineering").
SetClaimInt("clearance_level", 5).
SetExpiresAt(now + 3600)
token, _ := b.Sign()
var dept string
var clearance int64
// Verify and extract arbitrary claims in a single pass with 0 heap allocations
err := verifier.VerifyCustom(token, now, func(key, val []byte, isStr bool) bool {
switch string(key) {
case "department":
dept = string(val)
case "clearance_level":
clearance, _ = zerojwt.ParsePositiveInt(val)
}
return true // continue scanning
})
if err != nil {
fmt.Printf("VerifyCustom error: %v\n", err)
return
}
fmt.Printf("Department: %s, Clearance Level: %d\n", dept, clearance)
}
Output: Department: engineering, Clearance Level: 5
func (*Verifier) VerifyLarge ΒΆ
func (v *Verifier) VerifyLarge(tok []byte, nowUnix int64, out *ClaimsLarge) error
VerifyLarge validates the token and populates a ClaimsLarge struct (256B buffers per claim).
func (*Verifier) VerifyLargeWithScratch ΒΆ
func (v *Verifier) VerifyLargeWithScratch(tok []byte, nowUnix int64, out *ClaimsLarge, st *Scratch) error
VerifyLargeWithScratch validates the token into ClaimsLarge using a caller-supplied Scratch.
func (*Verifier) VerifyWithScratch ΒΆ
VerifyWithScratch performs the same verification as Verify using a caller-supplied Scratch, avoiding sync.Pool.Get/Put in single-threaded event loops (such as gnet with LockOSThread).