mirror of
https://github.com/jeremyd/ergo.git
synced 2026-08-01 11:43:06 -07:00
upgrade jwt lib
This commit is contained in:
@@ -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
|
||||
)
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user