Documentation
¶
Overview ¶
Package jwt issues and verifies JSON Web Tokens (RFC 7519) with the standard library: HS256, RS256, ES256 and EdDSA, an algorithm allowlist tied to each key (no algorithm confusion, never "none"), key ids with static or remote (JWKS) key sets that rotate, strict claim checks, a Guard for package auth, and rotating refresh tokens with reuse detection.
tok, err := jwt.Sign(key, jwt.Claims{Subject: u.AuthID(), ExpiresAt: time.Now().Add(15 * time.Minute)})
claims, err := verifier.Verify(ctx, tok)
See https://github.com/AlexGalhardo/vukem/blob/main/docs/authentication.md.
Example ¶
package main
import (
"context"
"crypto/ed25519"
"crypto/rand"
"fmt"
"time"
"github.com/AlexGalhardo/vukem/auth/jwt"
)
func main() {
_, priv, _ := ed25519.GenerateKey(rand.Reader)
key := jwt.EdDSA("2026-10", priv)
tok, _ := jwt.Sign(key, jwt.Claims{
Subject: "42", Issuer: "https://api.example.com", Audience: []string{"api"},
ExpiresAt: time.Now().Add(15 * time.Minute),
})
v := jwt.NewVerifier(jwt.StaticKeys(key), jwt.VerifyOptions{Issuer: "https://api.example.com", Audience: "api"})
claims, err := v.Verify(context.Background(), tok)
fmt.Println(claims.Subject, err)
}
Output: 42 <nil>
Index ¶
- Constants
- Variables
- func RefreshTokensMigration(id string) schema.Migration
- func Sign(k Key, c Claims) (string, error)
- type Claims
- type Guard
- type JWK
- type JWKS
- type Key
- type KeySet
- type RefreshTokens
- func (r *RefreshTokens) Issue(ctx context.Context, userID string) (string, error)
- func (r *RefreshTokens) Revoke(ctx context.Context, plain string) error
- func (r *RefreshTokens) RevokeUser(ctx context.Context, userID string) error
- func (r *RefreshTokens) Rotate(ctx context.Context, plain string) (userID, next string, err error)
- type RemoteJWKS
- type SharedKeySet
- type Verifier
- type VerifyOptions
Examples ¶
Constants ¶
const ( AlgHS256 = "HS256" AlgRS256 = "RS256" AlgES256 = "ES256" AlgEdDSA = "EdDSA" )
Supported algorithms.
Variables ¶
var ErrInvalid = errors.New("jwt: invalid token")
ErrInvalid is returned for every token that fails verification; the cause is wrapped for logs and never shown to clients.
var ErrRefreshReused = errors.New("jwt: refresh token reused; family revoked")
ErrRefreshReused is returned when a refresh token is presented again after it was rotated: the whole token family is revoked, since one of its copies was stolen.
Functions ¶
func RefreshTokensMigration ¶
RefreshTokensMigration creates the refresh_tokens table.
Types ¶
type Claims ¶
type Claims struct {
Issuer string
Subject string
Audience []string
ExpiresAt time.Time
NotBefore time.Time
IssuedAt time.Time
ID string
// Extra holds the other claims (decoded JSON values).
Extra map[string]any
}
Claims are the registered claims plus Extra private claims.
type Guard ¶
type Guard[U auth.Authenticatable] struct { // contains filtered or unexported fields }
Guard authenticates "Authorization: Bearer <jwt>" requests: the token must verify and its "sub" must name a user of the provider. It implements auth.Checker, so auth.Required(guard) protects routes.
func NewGuard ¶
func NewGuard[U auth.Authenticatable](name string, v *Verifier, p auth.UserProvider[U]) *Guard[U]
NewGuard returns a JWT guard named name. It panics when v.Err() reports a misconfiguration (a RemoteJWKS without Audience or Issuer), so the app fails at boot rather than refusing every token.
type JWK ¶
type JWK struct {
Kty string `json:"kty"`
Kid string `json:"kid,omitempty"`
Alg string `json:"alg,omitempty"`
Use string `json:"use,omitempty"`
N string `json:"n,omitempty"`
E string `json:"e,omitempty"`
Crv string `json:"crv,omitempty"`
X string `json:"x,omitempty"`
Y string `json:"y,omitempty"`
}
JWK is a public JSON Web Key (RFC 7517).
type JWKS ¶
type JWKS struct {
Keys []JWK `json:"keys"`
}
JWKS is a JSON Web Key Set.
func PublicJWKS ¶
PublicJWKS returns the public part of keys as a JWKS document, to serve at /.well-known/jwks.json. HMAC keys are never published.
type Key ¶
type Key struct {
// ID is the "kid" header.
ID string
// Alg is the only algorithm this key accepts.
Alg string
// Secret is the HS256 secret (at least 32 bytes).
Secret []byte
// Private signs (RSA, ECDSA P-256 or Ed25519); nil for verify-only keys.
Private crypto.Signer
// Public verifies.
Public crypto.PublicKey
}
Key is a signing or verification key bound to one algorithm.
type KeySet ¶
KeySet finds verification keys by id (kid); "" asks for the only key.
func StaticKeys ¶
StaticKeys is a fixed key set (current and previous keys during a rotation).
type RefreshTokens ¶
type RefreshTokens struct {
// TTL is the lifetime of each token (default 30 days).
TTL time.Duration
// Now is the clock (default time.Now).
Now func() time.Time
// contains filtered or unexported fields
}
RefreshTokens stores opaque, rotating refresh tokens (only their SHA-256 is kept). Each Rotate consumes the presented token and returns a new one of the same family; presenting a consumed token revokes the family.
func NewRefreshTokens ¶
func NewRefreshTokens(ex database.Executor) *RefreshTokens
NewRefreshTokens uses the refresh_tokens table (RefreshTokensMigration).
func (*RefreshTokens) Issue ¶
Issue starts a new token family for userID and returns the plain token.
func (*RefreshTokens) Revoke ¶
func (r *RefreshTokens) Revoke(ctx context.Context, plain string) error
Revoke ends the family of plain (logout); unknown tokens are ignored.
func (*RefreshTokens) RevokeUser ¶
func (r *RefreshTokens) RevokeUser(ctx context.Context, userID string) error
RevokeUser ends every refresh token of userID (password change).
type RemoteJWKS ¶
type RemoteJWKS struct {
URL string
// Client fetches the set (default: 10s timeout).
Client *http.Client
// MaxAge refreshes the cache after this long (default 1h).
MaxAge time.Duration
// MinRefresh limits refetches for unknown key ids (default 1m), so
// tokens with random kids cannot hammer the provider.
MinRefresh time.Duration
// Now is the clock (default time.Now).
Now func() time.Time
// contains filtered or unexported fields
}
RemoteJWKS fetches an identity provider's key set and refreshes it when a token names an unknown key id (rotation), at most once per MinRefresh.
func (*RemoteJWKS) SharedKeys ¶ added in v0.24.0
func (*RemoteJWKS) SharedKeys() bool
SharedKeys implements SharedKeySet: a provider's JWKS signs tokens for all of its clients.
type SharedKeySet ¶ added in v0.24.0
type SharedKeySet interface {
KeySet
}
SharedKeySet is a KeySet whose keys an identity provider also uses for its other clients (RemoteJWKS). A Verifier over one requires Audience and Issuer. Custom KeySets that wrap a RemoteJWKS should forward SharedKeys (embedding *RemoteJWKS does).
type Verifier ¶
type Verifier struct {
// contains filtered or unexported fields
}
Verifier checks tokens against a key set and claim rules.
func NewVerifier ¶
func NewVerifier(keys KeySet, opts VerifyOptions) *Verifier
NewVerifier returns a Verifier.
type VerifyOptions ¶
type VerifyOptions struct {
// Algorithms allowed (default: all supported); each key still only
// accepts its own algorithm.
Algorithms []string
// Issuer, when set, must equal "iss". Required with a *RemoteJWKS.
Issuer string
// Audience, when set, must be in "aud". Required with a *RemoteJWKS:
// an identity provider signs tokens for all of its clients with the
// same keys, so without it a token issued to another app is accepted.
Audience string
// InsecureSkipAudience accepts any "aud" with a *RemoteJWKS.
// Dangerous: tokens the provider issued to other apps pass.
InsecureSkipAudience bool
// InsecureSkipIssuer accepts any "iss" with a *RemoteJWKS.
// Dangerous: tokens from other tenants of a multi-tenant provider pass.
InsecureSkipIssuer bool
// Leeway tolerates clock skew (default 30s).
Leeway time.Duration
// AllowMissingExpiry accepts tokens without "exp" (off by default).
AllowMissingExpiry bool
// Now is the clock (default time.Now).
Now func() time.Time
}
VerifyOptions configures a Verifier.