upgrade jwt lib

This commit is contained in:
Shivaram Lingamneni
2026-07-21 05:23:43 +00:00
parent 260d0f045d
commit d9ad93b4b8
9 changed files with 43 additions and 26 deletions
+1 -1
View File
@@ -26,7 +26,7 @@ require (
require (
github.com/emersion/go-msgauth v0.7.0
github.com/ergochat/webpush-go/v2 v2.0.0
github.com/golang-jwt/jwt/v5 v5.3.0
github.com/golang-jwt/jwt/v5 v5.3.1
github.com/jackc/pgx/v5 v5.10.0
modernc.org/sqlite v1.54.0
)
+2
View File
@@ -37,6 +37,8 @@ github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY=
github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs=
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
+6 -5
View File
@@ -140,11 +140,12 @@ A common use case would be integrating with different 3rd party signature
providers, like key management services from various cloud providers or Hardware
Security Modules (HSMs) or to implement additional standards.
| Extension | Purpose | Repo |
| --------- | -------------------------------------------------------------------------------------------------------- | ------------------------------------------ |
| GCP | Integrates with multiple Google Cloud Platform signing tools (AppEngine, IAM API, Cloud KMS) | https://github.com/someone1/gcp-jwt-go |
| AWS | Integrates with AWS Key Management Service, KMS | https://github.com/matelang/jwt-go-aws-kms |
| JWKS | Provides support for JWKS ([RFC 7517](https://datatracker.ietf.org/doc/html/rfc7517)) as a `jwt.Keyfunc` | https://github.com/MicahParks/keyfunc |
| Extension | Purpose | Repo |
| --------- | -------------------------------------------------------------------------------------------------------- | ------------------------------------------------- |
| GCP | Integrates with multiple Google Cloud Platform signing tools (AppEngine, IAM API, Cloud KMS) | https://github.com/someone1/gcp-jwt-go |
| AWS | Integrates with AWS Key Management Service, KMS | https://github.com/matelang/jwt-go-aws-kms |
| JWKS | Provides support for JWKS ([RFC 7517](https://datatracker.ietf.org/doc/html/rfc7517)) as a `jwt.Keyfunc` | https://github.com/MicahParks/keyfunc |
| TPM | Integrates with Trusted Platform Module (TPM) | https://github.com/salrashid123/golang-jwt-tpm |
*Disclaimer*: Unless otherwise specified, these integrations are maintained by
third parties and should not be considered as a primary offer by any of the
+1 -1
View File
@@ -97,7 +97,7 @@ Backwards compatible API change that was missed in 2.0.0.
There were two major reasons for breaking backwards compatibility with this update. The first was a refactor required to expand the width of the RSA and HMAC-SHA signing implementations. There will likely be no required code changes to support this change.
The second update, while unfortunately requiring a small change in integration, is required to open up this library to other signing methods. Not all keys used for all signing methods have a single standard on-disk representation. Requiring `[]byte` as the type for all keys proved too limiting. Additionally, this implementation allows for pre-parsed tokens to be reused, which might matter in an application that parses a high volume of tokens with a small set of keys. Backwards compatibilty has been maintained for passing `[]byte` to the RSA signing methods, but they will also accept `*rsa.PublicKey` and `*rsa.PrivateKey`.
The second update, while unfortunately requiring a small change in integration, is required to open up this library to other signing methods. Not all keys used for all signing methods have a single standard on-disk representation. Requiring `[]byte` as the type for all keys proved too limiting. Additionally, this implementation allows for pre-parsed tokens to be reused, which might matter in an application that parses a high volume of tokens with a small set of keys. Backwards compatibility has been maintained for passing `[]byte` to the RSA signing methods, but they will also accept `*rsa.PublicKey` and `*rsa.PrivateKey`.
It is likely the only integration change required here will be to change `func(t *jwt.Token) ([]byte, error)` to `func(t *jwt.Token) (interface{}, error)` when calling `Parse`.
+13 -11
View File
@@ -76,13 +76,6 @@ func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyf
}
}
// Decode signature
token.Signature, err = p.DecodeSegment(parts[2])
if err != nil {
return token, newError("could not base64 decode signature", ErrTokenMalformed, err)
}
text := strings.Join(parts[0:2], ".")
// Lookup key(s)
if keyFunc == nil {
// keyFunc was not provided. short circuiting validation
@@ -94,11 +87,14 @@ func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyf
return token, newError("error while executing keyfunc", ErrTokenUnverifiable, err)
}
// Join together header and claims in order to verify them with the signature
text := strings.Join(parts[0:2], ".")
switch have := got.(type) {
case VerificationKeySet:
if len(have.Keys) == 0 {
return token, newError("keyfunc returned empty verification key set", ErrTokenUnverifiable)
}
// Iterate through keys and verify signature, skipping the rest when a match is found.
// Return the last error if no match is found.
for _, key := range have.Keys {
@@ -131,7 +127,7 @@ func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyf
return token, nil
}
// ParseUnverified parses the token but doesn't validate the signature.
// ParseUnverified parses the token but does not validate the signature.
//
// WARNING: Don't use this method unless you know what you're doing.
//
@@ -146,7 +142,7 @@ func (p *Parser) ParseUnverified(tokenString string, claims Claims) (token *Toke
token = &Token{Raw: tokenString}
// parse Header
// Parse Header
var headerBytes []byte
if headerBytes, err = p.DecodeSegment(parts[0]); err != nil {
return token, parts, newError("could not base64 decode header", ErrTokenMalformed, err)
@@ -155,7 +151,7 @@ func (p *Parser) ParseUnverified(tokenString string, claims Claims) (token *Toke
return token, parts, newError("could not JSON decode header", ErrTokenMalformed, err)
}
// parse Claims
// Parse Claims
token.Claims = claims
claimBytes, err := p.DecodeSegment(parts[1])
@@ -196,6 +192,12 @@ func (p *Parser) ParseUnverified(tokenString string, claims Claims) (token *Toke
return token, parts, newError("signing method (alg) is unspecified", ErrTokenUnverifiable)
}
// Parse token signature
token.Signature, err = p.DecodeSegment(parts[2])
if err != nil {
return token, parts, newError("could not base64 decode signature", ErrTokenMalformed, err)
}
return token, parts, nil
}
@@ -216,7 +218,7 @@ func splitToken(token string) ([]string, bool) {
parts[1] = claims
// One more cut to ensure the signature is the last part of the token and there are no more
// delimiters. This avoids an issue where malicious input could contain additional delimiters
// causing unecessary overhead parsing tokens.
// causing unnecessary overhead parsing tokens.
signature, _, unexpected := strings.Cut(remain, tokenDelimiter)
if unexpected {
return nil, false
+9 -3
View File
@@ -3,9 +3,7 @@ package jwt
import "time"
// ParserOption is used to implement functional-style options that modify the
// behavior of the parser. To add new options, just create a function (ideally
// beginning with With or Without) that returns an anonymous function that takes
// a *Parser type as input and manipulates its configuration accordingly.
// behavior of the parser.
type ParserOption func(*Parser)
// WithValidMethods is an option to supply algorithm methods that the parser
@@ -66,6 +64,14 @@ func WithExpirationRequired() ParserOption {
}
}
// WithNotBeforeRequired returns the ParserOption to make nbf claim required.
// By default nbf claim is optional.
func WithNotBeforeRequired() ParserOption {
return func(p *Parser) {
p.validator.requireNbf = true
}
}
// WithAudience configures the validator to require any of the specified
// audiences in the `aud` claim. Validation will fail if the audience is not
// listed in the token or the `aud` claim is missing.
+4 -2
View File
@@ -32,8 +32,8 @@ type Token struct {
Method SigningMethod // Method is the signing method used or to be used
Header map[string]any // Header is the first segment of the token in decoded form
Claims Claims // Claims is the second segment of the token in decoded form
Signature []byte // Signature is the third segment of the token in decoded form. Populated when you Parse a token
Valid bool // Valid specifies if the token is valid. Populated when you Parse/Verify a token
Signature []byte // Signature is the third segment of the token in decoded form. Populated when you [Parse] or sign a token
Valid bool // Valid specifies if the token is valid. Populated when you [Parse] a token
}
// New creates a new [Token] with the specified signing method and an empty map
@@ -71,6 +71,8 @@ func (t *Token) SignedString(key any) (string, error) {
return "", err
}
t.Signature = sig
return sstr + "." + t.EncodeSegment(sig), nil
}
+6 -2
View File
@@ -44,6 +44,9 @@ type Validator struct {
// requireExp specifies whether the exp claim is required
requireExp bool
// requireNbf specifies whether the nbf claim is required
requireNbf bool
// verifyIat specifies whether the iat (Issued At) claim will be verified.
// According to https://www.rfc-editor.org/rfc/rfc7519#section-4.1.6 this
// only specifies the age of the token, but no validation check is
@@ -111,8 +114,9 @@ func (v *Validator) Validate(claims Claims) error {
}
// We always need to check not-before, but usage of the claim itself is
// OPTIONAL.
if err = v.verifyNotBefore(claims, now, false); err != nil {
// OPTIONAL by default. requireNbf overrides this behavior and makes
// the nbf claim mandatory.
if err = v.verifyNotBefore(claims, now, v.requireNbf); err != nil {
errs = append(errs, err)
}
+1 -1
View File
@@ -41,7 +41,7 @@ github.com/go-sql-driver/mysql
# github.com/gofrs/flock v0.8.1
## explicit
github.com/gofrs/flock
# github.com/golang-jwt/jwt/v5 v5.3.0
# github.com/golang-jwt/jwt/v5 v5.3.1
## explicit; go 1.21
github.com/golang-jwt/jwt/v5
# github.com/google/uuid v1.6.0