Documentation
¶
Overview ¶
Package jwt is a pure-Go (no cgo) reimplementation of Ruby's `jwt` gem — the JSON Web Token library. It encodes and decodes JWS (JSON Web Signature) compact-serialisation tokens, byte-faithfully to the gem: given the same key, algorithm, payload and header, deterministic algorithms (HS*, RS*, PS-with- verification, none) produce identical tokens, and every algorithm (HS/RS/ES/PS) cross-verifies with MRI in both directions.
The whole surface is built on Go's standard crypto/* — crypto/hmac (HS), crypto/rsa PKCS1v15 (RS) and PSS (PS), crypto/ecdsa (ES) — so it is CGO-free and dependency-free.
tok, _ := jwt.Encode(map[string]any{"user": "amy", "exp": exp}, secret, "HS256", nil)
payload, header, _ := jwt.Decode(tok, secret, true, jwt.Options{Algorithms: []string{"HS256"}})
It is the JWT backend for go-embedded-ruby, but is a standalone, reusable module — a sibling of go-ruby-yaml (Psych) and go-ruby-regexp (Onigmo).
Index ¶
Constants ¶
const Version = "3.2.0"
Version mirrors the JWT::VERSION::STRING constant the gem exposes; it is the gem release this port tracks.
Variables ¶
var ( // ErrEncode is JWT::EncodeError — a token could not be produced. ErrEncode = errors.New("JWT::EncodeError") // ErrDecode is JWT::DecodeError, the root of every decode-time failure. ErrDecode = errors.New("JWT::DecodeError") // ErrVerification is JWT::VerificationError — the signature did not verify. ErrVerification = newParent("JWT::VerificationError", ErrDecode) // ErrIncorrectAlgorithm is JWT::IncorrectAlgorithm — the token's alg is not // among those the caller allowed (alg-confusion guard). ErrIncorrectAlgorithm = newParent("JWT::IncorrectAlgorithm", ErrDecode) // ErrExpiredSignature is JWT::ExpiredSignature — the exp claim is in the past. ErrExpiredSignature = newParent("JWT::ExpiredSignature", ErrDecode) // ErrImmatureSignature is JWT::ImmatureSignature — nbf is still in the future. ErrImmatureSignature = newParent("JWT::ImmatureSignature", ErrDecode) // ErrInvalidIat is JWT::InvalidIatError — the iat claim is malformed or future. ErrInvalidIat = newParent("JWT::InvalidIatError", ErrDecode) // ErrInvalidIssuer is JWT::InvalidIssuerError — the iss claim did not match. ErrInvalidIssuer = newParent("JWT::InvalidIssuerError", ErrDecode) // ErrInvalidAud is JWT::InvalidAudError — the aud claim did not match. ErrInvalidAud = newParent("JWT::InvalidAudError", ErrDecode) // ErrInvalidSub is JWT::InvalidSubError — the sub claim did not match. ErrInvalidSub = newParent("JWT::InvalidSubError", ErrDecode) // ErrInvalidJti is JWT::InvalidJtiError — the jti claim failed validation. ErrInvalidJti = newParent("JWT::InvalidJtiError", ErrDecode) // ErrInvalidPayload is JWT::InvalidPayload — a reserved claim has a bad type. ErrInvalidPayload = newParent("JWT::InvalidPayload", ErrDecode) // ErrMissingRequiredClaim is JWT::MissingRequiredClaim — a required claim is // absent from the payload. ErrMissingRequiredClaim = newParent("JWT::MissingRequiredClaim", ErrDecode) // ErrBase64Decode is JWT::Base64DecodeError — a segment was not valid base64url. ErrBase64Decode = newParent("JWT::Base64DecodeError", ErrDecode) // ErrJWK is JWT::JWKError — a JWK/JWKS could not be parsed or materialised into // a usable public key (malformed JSON, missing or bad key material, an // unsupported key type or curve). Like the gem's JWKError it is a DecodeError. ErrJWK = newParent("JWT::JWKError", ErrDecode) )
The sentinels below are the gem's exception classes. Match a specific one with errors.Is(err, jwt.ErrExpiredSignature), or the whole decode family with errors.Is(err, jwt.ErrDecode).
Functions ¶
func Decode ¶
Decode parses and (optionally) verifies a JWS compact token, mirroring the gem's JWT.decode(token, key, verify, options) => [payload, header]. It returns the decoded payload and header, both as *OrderedMap (so key order round-trips).
When verify is false the signature and claims are not checked and key/options may be nil/zero — the gem's "no verification" mode. When verify is true the signature is checked against key using an algorithm from opts.Algorithms (which must be non-empty), and the exp/nbf/iat/iss/aud/sub/jti/required-claim rules the options enable are applied.
func Encode ¶
Encode builds a signed JWS compact token from a payload, mirroring the gem's JWT.encode(payload, key, algorithm, header_fields).
The header is header_fields with "alg" set to algorithm: if header_fields already carries an "alg" key its position (and value) is kept, otherwise "alg" is appended last — exactly the gem's ordering. The header and payload are serialised with order-preserving compact JSON, base64url-encoded (no padding), joined with ".", signed, and the base64url signature appended.
key is the signing key for the chosen algorithm: an HMAC secret (string / []byte) for HS*, an *rsa.PrivateKey for RS*/PS*, an *ecdsa.PrivateKey for ES*. For the unsecured "none" algorithm key is ignored and the signature is empty.
payload and header_fields may be an *OrderedMap (to pin order), a map[string]any, or nil (header only — header_fields nil means just {"alg":...}).
Types ¶
type Error ¶
type Error struct {
// Kind names the gem exception class (e.g. "JWT::ExpiredSignature").
Kind string
// Message is the human-readable text, byte-for-byte the gem's message.
Message string
// contains filtered or unexported fields
}
Error is the shared interface of every error this package raises. It mirrors the gem's exception hierarchy, whose root is JWT::DecodeError < StandardError: a caller can match a single kind with errors.As, or the whole family with errors.Is(err, jwt.ErrDecode).
type JWK ¶
type JWK struct {
// Kty is "RSA" or "EC".
Kty string
// Crv is the EC curve name ("P-256"/"P-384"/"P-521"), empty for RSA.
Crv string
// N, E are the base64url RSA modulus and exponent (RSA only).
N, E string
// X, Y are the base64url EC coordinates (EC only).
X, Y string
// Kid is the key id. For a JWK built locally with NewJWK it is the gem's
// default key_digest (see below); for a JWK read from JSON with ParseJWK /
// ParseJWKS it is the provider-assigned "kid" carried on the wire, used to
// select the key by JWKS.Find / JWKS.Select.
Kid string
// Alg is the intended JWS algorithm ("RS256", "ES256", …) when the JWK
// declares one, or "" otherwise. Only populated by ParseJWK / ParseJWKS.
Alg string
// Use is the intended public-key use ("sig"/"enc") when declared, or "".
// Only populated by ParseJWK / ParseJWKS.
Use string
// contains filtered or unexported fields
}
JWK is a JSON Web Key (RFC 7517) for an RSA or EC public key — the export/import half of the gem's JWT::JWK. It mirrors the gem's export byte-for-byte: an RSA key exports {"kty":"RSA","n":..,"e":..,"kid":..}, an EC key {"kty":"EC","crv":..,"x":..,"y":..,"kid":..}.
Kid is the gem's default key id (JWK#kid), which is NOT the RFC 7638 thumbprint: the gem derives it as the lowercase-hex SHA-256 of the DER of an ASN.1 SEQUENCE of the key's two defining integers — (n, e) for RSA, (x, y) for EC — matching JWT::JWK's key_digest byte-for-byte. The RFC 7638 thumbprint (base64url) is available separately via Thumbprint.
func NewJWK ¶
NewJWK builds a JWK from an RSA or EC key (public, or the public half of a private key), mirroring JWT::JWK.new. The thumbprint Kid is computed on build.
func ParseJWK ¶
ParseJWK reads a single JSON Web Key from JSON and materialises its RSA (n/e) or EC (crv/x/y) public key, mirroring JWT::JWK.import for a lone key. The returned JWK carries the provider's "kid"/"alg"/"use" (for later selection) and the parsed public key (reachable via PublicKey). An unsupported key type is an error — unlike ParseJWKS, which skips a key it cannot use.
func (*JWK) Export ¶
func (j *JWK) Export() *OrderedMap
Export renders the JWK as an ordered object, key-for-key as the gem's JWK#export: RSA → kty,n,e,kid; EC → kty,crv,x,y,kid.
func (*JWK) PublicKey ¶
PublicKey returns the parsed crypto public key the JWK wraps, for verification.
func (*JWK) Thumbprint ¶
Thumbprint is the RFC 7638 key thumbprint: the unpadded base64url SHA-256 of the key's canonical JSON (members sorted, compact), byte-for-byte the gem's JWT::JWK::Thumbprint. It is distinct from Kid (the gem's default key_digest).
type JWKS ¶
type JWKS struct {
// contains filtered or unexported fields
}
JWKS is a set of JWKs, the key-lookup input to Decode for a token whose header carries a "kid" (the gem's JWT::JWK::Set). VerifyKey resolves the kid.
func ParseJWKS ¶
ParseJWKS reads a JSON Web Key Set ({"keys":[...]}) from JSON, materialising each RSA/EC key into a public key and keying it by the provider's "kid". A key whose type this library cannot use for JWS verification (e.g. an "oct" symmetric key) is skipped rather than failing the whole set, matching a client that ignores keys it has no use for; a key of a supported type with bad material is an error.
func (*JWKS) Keys ¶
Keys returns the set's keys in document order. The returned slice must not be mutated; it lets a consumer (e.g. an OIDC key set) adapt each imported JWK — its provider-assigned kid/alg/use and materialised public key — into its own representation.
func (*JWKS) Select ¶
Select resolves a verification key from the set by kid and (fallback) alg, mirroring how a client picks a JWKS key: a non-empty kid selects that exact key; an empty kid falls back to the sole signing-capable key whose type serves alg, rejecting an ambiguous (or empty) set. It is OIDC-agnostic — no issuer/audience logic — so any JWS consumer can reuse it.
type Options ¶
type Options struct {
// Algorithms is the allow-list of acceptable "alg" header values (the gem's
// algorithm:/algorithms: options). A token whose alg is not listed is rejected
// with IncorrectAlgorithm — the alg-confusion guard. Empty (with verify=true)
// is an error, matching the gem's "An algorithm must be specified".
Algorithms []string
// Leeway is the clock-skew allowance (seconds) applied to exp, nbf and iat.
Leeway int64
// ExpLeeway / NbfLeeway override Leeway for the respective claim when non-nil.
ExpLeeway *int64
NbfLeeway *int64
// VerifyExpiration toggles the exp check; the gem defaults it on, so this
// package treats it as on unless explicitly disabled via VerifyExpirationSet.
VerifyExpiration bool
VerifyExpirationSet bool // distinguishes "false" from "unset (=> true)"
// VerifyNotBefore toggles the nbf check (gem default on; same set-flag rule).
VerifyNotBefore bool
VerifyNotBeforeSet bool
// VerifyIat, when true, rejects a payload whose iat is malformed or in the
// future (the gem's verify_iat:).
VerifyIat bool
// Issuer + VerifyIss check the iss claim. Issuer may be a single string or a
// []string of acceptable issuers.
Issuer any
VerifyIss bool
// Audience + VerifyAud check the aud claim. Either side may be a string or a
// []string; the check passes when they intersect.
Audience any
VerifyAud bool
// Subject + VerifySub check the sub claim against an expected string.
Subject string
VerifySub bool
// VerifyJti, when true, requires the jti claim to be present and non-empty.
// A JtiValidator, when set, replaces that default with a custom predicate.
VerifyJti bool
JtiValidator func(jti any) bool
// RequiredClaims lists claim names that must be present in the payload
// (the gem's required_claims:).
RequiredClaims []string
}
Options mirrors the decode-options Hash the gem accepts as JWT.decode's fourth argument. The zero value verifies nothing beyond the signature and the always-on exp/nbf checks (which the gem also runs by default) — set the Verify* flags and their companion expected values to switch on claim validation.
type OrderedMap ¶
type OrderedMap struct {
// contains filtered or unexported fields
}
OrderedMap is an insertion-ordered string-keyed object, the analogue of a Ruby Hash. Encode accepts one as payload or header so a caller can pin claim / header order; Decode returns payload and header as *OrderedMap so key order round-trips.
func NewOrderedMap ¶
func NewOrderedMap() *OrderedMap
NewOrderedMap returns an empty ordered object.
func (*OrderedMap) Get ¶
func (m *OrderedMap) Get(key string) (any, bool)
Get returns the value stored under key and whether it was present.
func (*OrderedMap) Keys ¶
func (m *OrderedMap) Keys() []string
Keys returns the keys in insertion order.
func (*OrderedMap) Set ¶
func (m *OrderedMap) Set(key string, val any)
Set stores val under key, appending the key on first insertion and preserving its position on update (Ruby Hash#[]= semantics).