jwt

package
v1.1.4 Latest Latest
Warning

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

Go to latest
Published: Nov 29, 2025 License: Apache-2.0 Imports: 9 Imported by: 0

Documentation

Overview

Package jwt provides tools for parsing, verifying, and signing JSON Web Tokens (JWTs).

This package uses generics to allow users to define their own custom claims structures. A common pattern is to embed the provided Reserved claims struct and add extra fields for any other claims present in the token.

Basic Verification

Start by defining custom claims:

type Claims struct {
  jwt.Reserved
  Scope string         `json:"scp"`
  Extra map[string]any `json:",unknown"`
}

The top-level Verify function can be used for simple, one-off signature verification without claim validation:

keySet, err := jwk.ParseSet(`{"keys": [...]}`)
if err != nil { /* handle parsing error */ }
claims, err := jwt.Verify[Claims](keySet, []byte("eyJhb..."))

Advanced Validation

For advanced validation of claims like issuer, audience, and token age, create a reusable Verifier with the desired configuration:

verifier := jwt.NewVerifier[Claims](keySet).
	WithIssuer("foo", "bar").
	WithAudience("baz").
	WithLeeway(1 * time.Minute).
	WithMaxAge(1 * time.Hour)

claims, err := verifier.Verify([]byte("eyJhb..."))
if err != nil { /* handle validation error */ }
fmt.Println("Scope:", claims.Scope)

Basic Signing

The top-level Sign function can be used to create signed tokens from any JSON-serializable struct or map. This is useful for simple tokens where you manually handle all claims:

// keyPair must be a jwk.KeyPair (containing a private key)
claims := map[string]any{"sub": "user_123", "admin": true}
token, err := jwt.Sign(keyPair, claims)

Advanced Signing

To enforce policies like expiration or consistent issuers, create a reusable Signer. Your claims struct must implement MutableClaims (embedding jwt.Reserved handles this automatically).

signer := jwt.NewSigner(keyPair).
    WithIssuer("https://api.example.com").
    WithLifetime(1 * time.Hour)

// The signer will automatically set "iss", "iat", and "exp" on the struct.
claims := &MyClaims{
    Reserved: jwt.Reserved{Subject: "user_123"},
    Scope:    "admin",
}
token, err := signer.Sign(claims)

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrKeyNotFound is returned when no matching key is found in the JWK set.
	ErrKeyNotFound = errors.New("no matching key found")
	// ErrInvalidSignature is returned when the token's signature differs from
	// the computed signature.
	ErrInvalidSignature = errors.New("invalid signature")
)
View Source
var (
	// ErrInvalidIssuer signals that the "iss" claim did not match any of the
	// expected issuers.
	ErrInvalidIssuer = errors.New("invalid issuer")
	// ErrInvalidAudience signals that the "aud" claim did not match any of the
	// expected audiences.
	ErrInvalidAudience = errors.New("invalid audience")
	// ErrTokenExpired signals that the "exp" claim is in the past.
	ErrTokenExpired = errors.New("token is expired")
	// ErrTokenNotYetActive signals that the "nbf" claim is in the future.
	ErrTokenNotYetActive = errors.New("token not yet active")
	// ErrTokenTooOld signals that the "iat" claim is further in the past than
	// the configured maximum age.
	ErrTokenTooOld = errors.New("token is too old")
)

Functions

func Sign

func Sign(k jwk.KeyPair, claims any) ([]byte, error)

Sign creates a new signed JWT using the provided KeyPair and claims.

It marshals the claims using encoding/json/v2, creates a header based on the key's properties, and signs the payload. The claims argument can be any type that serializes to a JSON object.

func Verify

func Verify[T Claims](set jwk.Set, in []byte) (T, error)

Verify first parses a JWT and then verifies its signature against a given key set. The type parameter T specifies the target struct for the token's claims.

This function only checks the cryptographic signature, not the content of the claims. For claim validation (e.g., issuer, audience, expiration), create and configure a Verifier. It is a shorthand for Parse followed by calling Verify on the resulting Token.

Types

type Claims

type Claims interface {
	// ID returns the "jti" (JWT ID) claim, or an empty string if absent.
	ID() string
	// Subject returns the "sub" (Subject) claim, or an empty string if absent.
	Subject() string
	// Issuer returns the "iss" (Issuer) claim, or an empty string if absent.
	Issuer() string
	// Audience returns the "aud" (Audience) claim, or nil if absent.
	Audience() []string
	// IssuedAt returns the "iat" (Issued At) claim, or the zero time if absent.
	IssuedAt() time.Time
	// ExpiresAt returns the "exp" (Expires At) claim, or the zero time if absent.
	ExpiresAt() time.Time
	// NotBefore returns the "nbf" (Not Before) claim, or the zero time if absent.
	NotBefore() time.Time
}

Claims provides access to the standard JWT claims. It is used by Verifier for claim validation.

type Header jwk.Hint

Header represents the decoded JOSE header of a JWT.

type MutableClaims

type MutableClaims interface {
	Claims

	// SetID sets the "jti" (JWT ID) claim.
	SetID(id string)
	// SetSubject sets the "sub" (Subject) claim.
	SetSubject(sub string)
	// SetIssuer sets the "iss" (Issuer) claim.
	SetIssuer(iss string)
	// SetAudience sets the "aud" (Audience) claim.
	SetAudience(aud []string)
	// SetIssuedAt sets the "iat" (Issued At) claim.
	SetIssuedAt(t time.Time)
	// SetExpiresAt sets the "exp" (Expires At) claim.
	SetExpiresAt(t time.Time)
	// SetNotBefore sets the "nbf" (Not Before) claim.
	SetNotBefore(t time.Time)
}

MutableClaims extends Claims with setters for standard JWT claims.

The setter methods are not safe for concurrent use and should only be called during token creation.

type Reserved

type Reserved struct {
	Jti string    `json:"jti,omitempty"`            // JWT ID
	Sub string    `json:"sub,omitempty"`            // Subject
	Iss string    `json:"iss,omitempty"`            // Issuer
	Aud audience  `json:"aud,omitempty"`            // Audience
	Iat time.Time `json:"iat,omitzero,format:unix"` // Issued At
	Exp time.Time `json:"exp,omitzero,format:unix"` // Expires At
	Nbf time.Time `json:"nbf,omitzero,format:unix"` // Not Before
}

Reserved contains the standard registered claims for a JWT. It implements the Claims interface and should be embedded in custom claims structs to enable standard claim handling.

func (*Reserved) Audience

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

func (*Reserved) ExpiresAt

func (r *Reserved) ExpiresAt() time.Time

func (*Reserved) ID

func (r *Reserved) ID() string

func (*Reserved) IssuedAt

func (r *Reserved) IssuedAt() time.Time

func (*Reserved) Issuer

func (r *Reserved) Issuer() string

func (*Reserved) NotBefore

func (r *Reserved) NotBefore() time.Time

func (*Reserved) SetAudience

func (r *Reserved) SetAudience(aud []string)

func (*Reserved) SetExpiresAt

func (r *Reserved) SetExpiresAt(t time.Time)

func (*Reserved) SetID

func (r *Reserved) SetID(id string)

func (*Reserved) SetIssuedAt

func (r *Reserved) SetIssuedAt(t time.Time)

func (*Reserved) SetIssuer

func (r *Reserved) SetIssuer(iss string)

func (*Reserved) SetNotBefore

func (r *Reserved) SetNotBefore(t time.Time)

func (*Reserved) SetSubject

func (r *Reserved) SetSubject(sub string)

func (*Reserved) Subject

func (r *Reserved) Subject() string

type Signer

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

Signer is a configured, reusable JWT creator. It allows setting default claims (like Issuer and Audience) and enforcing token lifetime (Expiration).

func NewSigner

func NewSigner(keys ...jwk.KeyPair) *Signer

NewSigner creates a new Signer that uses the provided key pool for signing. At least one key pair must be provided; otherwise, it panics. If multiple keys are given, they will be rotated through in a round-robin fashion to ensure even usage across the key pool. Further configuration can be applied using the With... setters.

func (*Signer) Sign

func (s *Signer) Sign(claims MutableClaims) ([]byte, error)

Sign applies the signer's configuration (issuer, audience, and temporal validity) directly to the mutable claims object, then signs it.

func (*Signer) WithAudience

func (s *Signer) WithAudience(aud ...string) *Signer

WithAudience sets the "aud" (Audience) claim. If the user-provided claims already contain an audience, this configuration will overwrite it.

This method is not thread-safe and should be called only during setup.

func (*Signer) WithClock ��

func (s *Signer) WithClock(now func() time.Time) *Signer

WithClock sets the function used to retrieve the current time when timestamping tokens ("iat", "nbf", "exp"). This is useful for deterministic testing. The default is time.Now.

This method is not thread-safe and should be called only during setup.

func (*Signer) WithIssuedAt

func (s *Signer) WithIssuedAt(use bool) *Signer

WithIssuedAt enables or disables automatic setting of the "iat" (Issued At) claim for all tokens created by this signer. It is enabled by default and will be stamped with the current time.

This method is not thread-safe and should be called only during setup.

func (*Signer) WithIssuer

func (s *Signer) WithIssuer(iss string) *Signer

WithIssuer sets the "iss" (Issuer) claim for all tokens created by this signer. If the user-provided claims already contain an issuer, this configuration will overwrite it.

This method is not thread-safe and should be called only during setup.

func (*Signer) WithLifetime

func (s *Signer) WithLifetime(d time.Duration) *Signer

WithLifetime sets the duration for which tokens are valid. It calculates the "exp" (Expires At) claim by adding this duration to the current time. If zero (default), no "exp" claim is added unless provided in the input claims.

This method is not thread-safe and should be called only during setup.

type Token

type Token[T Claims] interface {
	// Header returns the token's header parameters.
	Header() Header
	// Claims returns the token's payload claims.
	Claims() T
	// Verify checks the token's signature using the provided JWK set.
	// It returns ErrKeyNotFound if no matching key is found or
	// ErrInvalidSignature if the signature is incorrect.
	Verify(set jwk.Set) error
}

Token represents a parsed, but not necessarily verified, JWT. The generic type T is the user-defined claims structure.

func Parse

func Parse[T Claims](in []byte) (Token[T], error)

Parse decodes a JWT from its compact serialization format into a Token without verifying the signature. The type parameter T specifies the target struct for the token's claims. If the token is malformed or the payload does not unmarshal into T (using encoding/json/v2), an error is returned.

type Verifier

type Verifier[T Claims] struct {
	// contains filtered or unexported fields
}

Verifier is a configured, reusable JWT verifier. The type parameter T is the user-defined struct for the token's claims. It must implement the Claims interface, or else verification will always fail.

func NewVerifier

func NewVerifier[T Claims](set jwk.Set) *Verifier[T]

NewVerifier creates a new verifier bound to a specific JWK set. The type parameter T is the user-defined struct for the token's claims. Further configuration can be applied using the With... setters.

func (*Verifier[T]) Verify

func (v *Verifier[T]) Verify(in []byte) (T, error)

Verify parses a token from its compact serialization, verifies its signature against the verifier's key set, and validates its claims according to the verifier's configuration.

func (*Verifier[T]) WithAudiences

func (v *Verifier[T]) WithAudiences(aud ...string) *Verifier[T]

WithAudiences adds one or more trusted audiences to the verifier. If the token's "aud" claim is missing or does not contain at least one of these values, it will be rejected. This option can be used multiple times to append additional values. By default, no audience validation is performed.

This method is not thread-safe and should be called only during setup.

func (*Verifier[T]) WithClock

func (v *Verifier[T]) WithClock(now func() time.Time) *Verifier[T]

WithClock sets the function used to retrieve the current time during validation. This is useful for deterministic testing or synchronizing with an external time source. The default is time.Now.

This method is not thread-safe and should be called only during setup.

func (*Verifier[T]) WithIssuers

func (v *Verifier[T]) WithIssuers(iss ...string) *Verifier[T]

WithIssuers adds one or more trusted issuers to the verifier. If a token's "iss" claim is missing or does not match one of these, it will be rejected. This option can be used multiple times to append additional values. By default, no issuer validation is performed.

This method is not thread-safe and should be called only during setup.

func (*Verifier[T]) WithLeeway

func (v *Verifier[T]) WithLeeway(d time.Duration) *Verifier[T]

WithLeeway sets a grace period to allow for clock skew in temporal validations of the "exp", "nbf", and "iat" claims. It is subtracted from or added to the current time as appropriate. The default is zero, meaning no leeway. Negative values will be ignored.

This method is not thread-safe and should be called only during setup.

func (*Verifier[T]) WithMaxAge

func (v *Verifier[T]) WithMaxAge(d time.Duration) *Verifier[T]

WithMaxAge sets the maximum age for tokens based on their "iat" claim. Tokens without an "iat" claim will no longer be accepted. The default is zero, meaning no age validation. Negative values will be ignored.

This method is not thread-safe and should be called only during setup.