[chore] bump to code.superseriousbusiness.org/oauth2/v4@ssb-v4.5.3-2 (#4367)

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4367
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
This commit is contained in:
kim 2025-08-12 16:04:30 +02:00 committed by kim
commit 1edc0f7b3c
22 changed files with 139 additions and 200 deletions

4
go.mod
View file

@ -12,7 +12,7 @@ require (
code.superseriousbusiness.org/activity v1.16.0 code.superseriousbusiness.org/activity v1.16.0
code.superseriousbusiness.org/exif-terminator v0.11.0 code.superseriousbusiness.org/exif-terminator v0.11.0
code.superseriousbusiness.org/httpsig v1.4.0 code.superseriousbusiness.org/httpsig v1.4.0
code.superseriousbusiness.org/oauth2/v4 v4.5.4-0.20250606121655-9d54ef189d42 code.superseriousbusiness.org/oauth2/v4 v4.5.4-0.20250812115401-3961e46a7384
codeberg.org/gruf/go-bitutil v1.1.0 codeberg.org/gruf/go-bitutil v1.1.0
codeberg.org/gruf/go-bytesize v1.0.3 codeberg.org/gruf/go-bytesize v1.0.3
codeberg.org/gruf/go-byteutil v1.3.0 codeberg.org/gruf/go-byteutil v1.3.0
@ -147,7 +147,7 @@ require (
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b // indirect github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b // indirect
github.com/goccy/go-json v0.10.5 // indirect github.com/goccy/go-json v0.10.5 // indirect
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect github.com/golang-jwt/jwt/v5 v5.3.0 // indirect
github.com/golang/geo v0.0.0-20200319012246-673a6f80352d // indirect github.com/golang/geo v0.0.0-20200319012246-673a6f80352d // indirect
github.com/gorilla/context v1.1.2 // indirect github.com/gorilla/context v1.1.2 // indirect
github.com/gorilla/css v1.0.1 // indirect github.com/gorilla/css v1.0.1 // indirect

8
go.sum generated
View file

@ -8,8 +8,8 @@ code.superseriousbusiness.org/go-png-image-structure/v2 v2.3.0 h1:I512jiIeXDC4//
code.superseriousbusiness.org/go-png-image-structure/v2 v2.3.0/go.mod h1:SNHomXNW88o1pFfLHpD4KsCZLfcr4z5dm+xcX5SV10A= code.superseriousbusiness.org/go-png-image-structure/v2 v2.3.0/go.mod h1:SNHomXNW88o1pFfLHpD4KsCZLfcr4z5dm+xcX5SV10A=
code.superseriousbusiness.org/httpsig v1.4.0 h1:g9+KQMoTG0oR0II5gYb5pVVdNjbc7CiiuqK8vcZjeQg= code.superseriousbusiness.org/httpsig v1.4.0 h1:g9+KQMoTG0oR0II5gYb5pVVdNjbc7CiiuqK8vcZjeQg=
code.superseriousbusiness.org/httpsig v1.4.0/go.mod h1:i2AKpj/WbA/o/UTvia9TAREzt0jP1AH3T1Uxjyhdzlw= code.superseriousbusiness.org/httpsig v1.4.0/go.mod h1:i2AKpj/WbA/o/UTvia9TAREzt0jP1AH3T1Uxjyhdzlw=
code.superseriousbusiness.org/oauth2/v4 v4.5.4-0.20250606121655-9d54ef189d42 h1:MZXZaWeBV7eal2E0Evrwmo0Q/kwfy5F4S/fPTkrtvNQ= code.superseriousbusiness.org/oauth2/v4 v4.5.4-0.20250812115401-3961e46a7384 h1:eJzULGUyhHGk2DdQxX/jbH9FKZOyoIF90p3dzukCfLA=
code.superseriousbusiness.org/oauth2/v4 v4.5.4-0.20250606121655-9d54ef189d42/go.mod h1:+7E3Zyp5xPGSWiKxOMXnfvHMBdGjoIZF/Ozv+WIHRgA= code.superseriousbusiness.org/oauth2/v4 v4.5.4-0.20250812115401-3961e46a7384/go.mod h1:4x61i4C725jkXOpnUPFNfmiEthF6FZc/byADbalp+F8=
codeberg.org/gruf/go-bitutil v1.1.0 h1:U1Q+A1mtnPk+npqYrlRBc9ar2C5hYiBd17l1Wrp2Bt8= codeberg.org/gruf/go-bitutil v1.1.0 h1:U1Q+A1mtnPk+npqYrlRBc9ar2C5hYiBd17l1Wrp2Bt8=
codeberg.org/gruf/go-bitutil v1.1.0/go.mod h1:rGibFevYTQfYKcPv0Df5KpG8n5xC3AfD4d/UgYeoNy0= codeberg.org/gruf/go-bitutil v1.1.0/go.mod h1:rGibFevYTQfYKcPv0Df5KpG8n5xC3AfD4d/UgYeoNy0=
codeberg.org/gruf/go-bytesize v1.0.3 h1:Tz8tCxhPLeyM5VryuBNjUHgKmLj4Bx9RbPaUSA3qg6g= codeberg.org/gruf/go-bytesize v1.0.3 h1:Tz8tCxhPLeyM5VryuBNjUHgKmLj4Bx9RbPaUSA3qg6g=
@ -214,8 +214,8 @@ github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJA
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8= github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
github.com/golang/geo v0.0.0-20200319012246-673a6f80352d h1:C/hKUcHT483btRbeGkrRjJz+Zbcj8audldIi9tRJDCc= github.com/golang/geo v0.0.0-20200319012246-673a6f80352d h1:C/hKUcHT483btRbeGkrRjJz+Zbcj8audldIi9tRJDCc=
github.com/golang/geo v0.0.0-20200319012246-673a6f80352d/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= github.com/golang/geo v0.0.0-20200319012246-673a6f80352d/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=

View file

@ -155,7 +155,7 @@ stored in base64 encoded form, which was redundant with the information in the
type Token struct { type Token struct {
Raw string // Raw contains the raw token Raw string // Raw contains the raw token
Method SigningMethod // Method is the signing method used or to be used Method SigningMethod // Method is the signing method used or to be used
Header map[string]interface{} // Header is the first segment of the token in decoded form 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 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 Signature []byte // Signature is the third segment of the token in decoded form
Valid bool // Valid specifies if the token is valid Valid bool // Valid specifies if the token is valid

View file

@ -55,7 +55,7 @@ func (m *SigningMethodECDSA) Alg() string {
// Verify implements token verification for the SigningMethod. // Verify implements token verification for the SigningMethod.
// For this verify method, key must be an ecdsa.PublicKey struct // For this verify method, key must be an ecdsa.PublicKey struct
func (m *SigningMethodECDSA) Verify(signingString string, sig []byte, key interface{}) error { func (m *SigningMethodECDSA) Verify(signingString string, sig []byte, key any) error {
// Get the key // Get the key
var ecdsaKey *ecdsa.PublicKey var ecdsaKey *ecdsa.PublicKey
switch k := key.(type) { switch k := key.(type) {
@ -89,7 +89,7 @@ func (m *SigningMethodECDSA) Verify(signingString string, sig []byte, key interf
// Sign implements token signing for the SigningMethod. // Sign implements token signing for the SigningMethod.
// For this signing method, key must be an ecdsa.PrivateKey struct // For this signing method, key must be an ecdsa.PrivateKey struct
func (m *SigningMethodECDSA) Sign(signingString string, key interface{}) ([]byte, error) { func (m *SigningMethodECDSA) Sign(signingString string, key any) ([]byte, error) {
// Get the key // Get the key
var ecdsaKey *ecdsa.PrivateKey var ecdsaKey *ecdsa.PrivateKey
switch k := key.(type) { switch k := key.(type) {

View file

@ -23,7 +23,7 @@ func ParseECPrivateKeyFromPEM(key []byte) (*ecdsa.PrivateKey, error) {
} }
// Parse the key // Parse the key
var parsedKey interface{} var parsedKey any
if parsedKey, err = x509.ParseECPrivateKey(block.Bytes); err != nil { if parsedKey, err = x509.ParseECPrivateKey(block.Bytes); err != nil {
if parsedKey, err = x509.ParsePKCS8PrivateKey(block.Bytes); err != nil { if parsedKey, err = x509.ParsePKCS8PrivateKey(block.Bytes); err != nil {
return nil, err return nil, err
@ -50,7 +50,7 @@ func ParseECPublicKeyFromPEM(key []byte) (*ecdsa.PublicKey, error) {
} }
// Parse the key // Parse the key
var parsedKey interface{} var parsedKey any
if parsedKey, err = x509.ParsePKIXPublicKey(block.Bytes); err != nil { if parsedKey, err = x509.ParsePKIXPublicKey(block.Bytes); err != nil {
if cert, err := x509.ParseCertificate(block.Bytes); err == nil { if cert, err := x509.ParseCertificate(block.Bytes); err == nil {
parsedKey = cert.PublicKey parsedKey = cert.PublicKey

View file

@ -33,7 +33,7 @@ func (m *SigningMethodEd25519) Alg() string {
// Verify implements token verification for the SigningMethod. // Verify implements token verification for the SigningMethod.
// For this verify method, key must be an ed25519.PublicKey // For this verify method, key must be an ed25519.PublicKey
func (m *SigningMethodEd25519) Verify(signingString string, sig []byte, key interface{}) error { func (m *SigningMethodEd25519) Verify(signingString string, sig []byte, key any) error {
var ed25519Key ed25519.PublicKey var ed25519Key ed25519.PublicKey
var ok bool var ok bool
@ -55,7 +55,7 @@ func (m *SigningMethodEd25519) Verify(signingString string, sig []byte, key inte
// Sign implements token signing for the SigningMethod. // Sign implements token signing for the SigningMethod.
// For this signing method, key must be an ed25519.PrivateKey // For this signing method, key must be an ed25519.PrivateKey
func (m *SigningMethodEd25519) Sign(signingString string, key interface{}) ([]byte, error) { func (m *SigningMethodEd25519) Sign(signingString string, key any) ([]byte, error) {
var ed25519Key crypto.Signer var ed25519Key crypto.Signer
var ok bool var ok bool

View file

@ -24,7 +24,7 @@ func ParseEdPrivateKeyFromPEM(key []byte) (crypto.PrivateKey, error) {
} }
// Parse the key // Parse the key
var parsedKey interface{} var parsedKey any
if parsedKey, err = x509.ParsePKCS8PrivateKey(block.Bytes); err != nil { if parsedKey, err = x509.ParsePKCS8PrivateKey(block.Bytes); err != nil {
return nil, err return nil, err
} }
@ -49,7 +49,7 @@ func ParseEdPublicKeyFromPEM(key []byte) (crypto.PublicKey, error) {
} }
// Parse the key // Parse the key
var parsedKey interface{} var parsedKey any
if parsedKey, err = x509.ParsePKIXPublicKey(block.Bytes); err != nil { if parsedKey, err = x509.ParsePKIXPublicKey(block.Bytes); err != nil {
return nil, err return nil, err
} }

View file

@ -2,6 +2,7 @@ package jwt
import ( import (
"errors" "errors"
"fmt"
"strings" "strings"
) )
@ -47,3 +48,42 @@ func joinErrors(errs ...error) error {
errs: errs, errs: errs,
} }
} }
// Unwrap implements the multiple error unwrapping for this error type, which is
// possible in Go 1.20.
func (je joinedError) Unwrap() []error {
return je.errs
}
// newError creates a new error message with a detailed error message. The
// message will be prefixed with the contents of the supplied error type.
// Additionally, more errors, that provide more context can be supplied which
// will be appended to the message. This makes use of Go 1.20's possibility to
// include more than one %w formatting directive in [fmt.Errorf].
//
// For example,
//
// newError("no keyfunc was provided", ErrTokenUnverifiable)
//
// will produce the error string
//
// "token is unverifiable: no keyfunc was provided"
func newError(message string, err error, more ...error) error {
var format string
var args []any
if message != "" {
format = "%w: %s"
args = []any{err, message}
} else {
format = "%w"
args = []any{err}
}
for _, e := range more {
format += ": %w"
args = append(args, e)
}
err = fmt.Errorf(format, args...)
return err
}

View file

@ -1,47 +0,0 @@
//go:build go1.20
// +build go1.20
package jwt
import (
"fmt"
)
// Unwrap implements the multiple error unwrapping for this error type, which is
// possible in Go 1.20.
func (je joinedError) Unwrap() []error {
return je.errs
}
// newError creates a new error message with a detailed error message. The
// message will be prefixed with the contents of the supplied error type.
// Additionally, more errors, that provide more context can be supplied which
// will be appended to the message. This makes use of Go 1.20's possibility to
// include more than one %w formatting directive in [fmt.Errorf].
//
// For example,
//
// newError("no keyfunc was provided", ErrTokenUnverifiable)
//
// will produce the error string
//
// "token is unverifiable: no keyfunc was provided"
func newError(message string, err error, more ...error) error {
var format string
var args []any
if message != "" {
format = "%w: %s"
args = []any{err, message}
} else {
format = "%w"
args = []any{err}
}
for _, e := range more {
format += ": %w"
args = append(args, e)
}
err = fmt.Errorf(format, args...)
return err
}

View file

@ -1,78 +0,0 @@
//go:build !go1.20
// +build !go1.20
package jwt
import (
"errors"
"fmt"
)
// Is implements checking for multiple errors using [errors.Is], since multiple
// error unwrapping is not possible in versions less than Go 1.20.
func (je joinedError) Is(err error) bool {
for _, e := range je.errs {
if errors.Is(e, err) {
return true
}
}
return false
}
// wrappedErrors is a workaround for wrapping multiple errors in environments
// where Go 1.20 is not available. It basically uses the already implemented
// functionality of joinedError to handle multiple errors with supplies a
// custom error message that is identical to the one we produce in Go 1.20 using
// multiple %w directives.
type wrappedErrors struct {
msg string
joinedError
}
// Error returns the stored error string
func (we wrappedErrors) Error() string {
return we.msg
}
// newError creates a new error message with a detailed error message. The
// message will be prefixed with the contents of the supplied error type.
// Additionally, more errors, that provide more context can be supplied which
// will be appended to the message. Since we cannot use of Go 1.20's possibility
// to include more than one %w formatting directive in [fmt.Errorf], we have to
// emulate that.
//
// For example,
//
// newError("no keyfunc was provided", ErrTokenUnverifiable)
//
// will produce the error string
//
// "token is unverifiable: no keyfunc was provided"
func newError(message string, err error, more ...error) error {
// We cannot wrap multiple errors here with %w, so we have to be a little
// bit creative. Basically, we are using %s instead of %w to produce the
// same error message and then throw the result into a custom error struct.
var format string
var args []any
if message != "" {
format = "%s: %s"
args = []any{err, message}
} else {
format = "%s"
args = []any{err}
}
errs := []error{err}
for _, e := range more {
format += ": %s"
args = append(args, e)
errs = append(errs, e)
}
err = &wrappedErrors{
msg: fmt.Sprintf(format, args...),
joinedError: joinedError{errs: errs},
}
return err
}

View file

@ -55,7 +55,7 @@ func (m *SigningMethodHMAC) Alg() string {
// about this, and why we intentionally are not supporting string as a key can // about this, and why we intentionally are not supporting string as a key can
// be found on our usage guide // be found on our usage guide
// https://golang-jwt.github.io/jwt/usage/signing_methods/#signing-methods-and-key-types. // https://golang-jwt.github.io/jwt/usage/signing_methods/#signing-methods-and-key-types.
func (m *SigningMethodHMAC) Verify(signingString string, sig []byte, key interface{}) error { func (m *SigningMethodHMAC) Verify(signingString string, sig []byte, key any) error {
// Verify the key is the right type // Verify the key is the right type
keyBytes, ok := key.([]byte) keyBytes, ok := key.([]byte)
if !ok { if !ok {
@ -88,7 +88,7 @@ func (m *SigningMethodHMAC) Verify(signingString string, sig []byte, key interfa
// cryptographically random source, e.g. crypto/rand. Additional information // cryptographically random source, e.g. crypto/rand. Additional information
// about this, and why we intentionally are not supporting string as a key can // about this, and why we intentionally are not supporting string as a key can
// be found on our usage guide https://golang-jwt.github.io/jwt/usage/signing_methods/. // be found on our usage guide https://golang-jwt.github.io/jwt/usage/signing_methods/.
func (m *SigningMethodHMAC) Sign(signingString string, key interface{}) ([]byte, error) { func (m *SigningMethodHMAC) Sign(signingString string, key any) ([]byte, error) {
if keyBytes, ok := key.([]byte); ok { if keyBytes, ok := key.([]byte); ok {
if !m.Hash.Available() { if !m.Hash.Available() {
return nil, ErrHashUnavailable return nil, ErrHashUnavailable

View file

@ -5,9 +5,9 @@ import (
"fmt" "fmt"
) )
// MapClaims is a claims type that uses the map[string]interface{} for JSON // MapClaims is a claims type that uses the map[string]any for JSON
// decoding. This is the default claims type if you don't supply one // decoding. This is the default claims type if you don't supply one
type MapClaims map[string]interface{} type MapClaims map[string]any
// GetExpirationTime implements the Claims interface. // GetExpirationTime implements the Claims interface.
func (m MapClaims) GetExpirationTime() (*NumericDate, error) { func (m MapClaims) GetExpirationTime() (*NumericDate, error) {
@ -73,7 +73,7 @@ func (m MapClaims) parseClaimsString(key string) (ClaimStrings, error) {
cs = append(cs, v) cs = append(cs, v)
case []string: case []string:
cs = v cs = v
case []interface{}: case []any:
for _, a := range v { for _, a := range v {
vs, ok := a.(string) vs, ok := a.(string)
if !ok { if !ok {
@ -92,7 +92,7 @@ func (m MapClaims) parseClaimsString(key string) (ClaimStrings, error) {
func (m MapClaims) parseString(key string) (string, error) { func (m MapClaims) parseString(key string) (string, error) {
var ( var (
ok bool ok bool
raw interface{} raw any
iss string iss string
) )
raw, ok = m[key] raw, ok = m[key]

View file

@ -25,7 +25,7 @@ func (m *signingMethodNone) Alg() string {
} }
// Only allow 'none' alg type if UnsafeAllowNoneSignatureType is specified as the key // Only allow 'none' alg type if UnsafeAllowNoneSignatureType is specified as the key
func (m *signingMethodNone) Verify(signingString string, sig []byte, key interface{}) (err error) { func (m *signingMethodNone) Verify(signingString string, sig []byte, key any) (err error) {
// Key must be UnsafeAllowNoneSignatureType to prevent accidentally // Key must be UnsafeAllowNoneSignatureType to prevent accidentally
// accepting 'none' signing method // accepting 'none' signing method
if _, ok := key.(unsafeNoneMagicConstant); !ok { if _, ok := key.(unsafeNoneMagicConstant); !ok {
@ -41,7 +41,7 @@ func (m *signingMethodNone) Verify(signingString string, sig []byte, key interfa
} }
// Only allow 'none' signing if UnsafeAllowNoneSignatureType is specified as the key // Only allow 'none' signing if UnsafeAllowNoneSignatureType is specified as the key
func (m *signingMethodNone) Sign(signingString string, key interface{}) ([]byte, error) { func (m *signingMethodNone) Sign(signingString string, key any) ([]byte, error) {
if _, ok := key.(unsafeNoneMagicConstant); ok { if _, ok := key.(unsafeNoneMagicConstant); ok {
return []byte{}, nil return []byte{}, nil
} }

View file

@ -66,20 +66,37 @@ func WithExpirationRequired() ParserOption {
} }
} }
// WithAudience configures the validator to require the specified audience in // WithAudience configures the validator to require any of the specified
// the `aud` claim. Validation will fail if the audience is not listed in the // audiences in the `aud` claim. Validation will fail if the audience is not
// token or the `aud` claim is missing. // listed in the token or the `aud` claim is missing.
// //
// NOTE: While the `aud` claim is OPTIONAL in a JWT, the handling of it is // NOTE: While the `aud` claim is OPTIONAL in a JWT, the handling of it is
// application-specific. Since this validation API is helping developers in // application-specific. Since this validation API is helping developers in
// writing secure application, we decided to REQUIRE the existence of the claim, // writing secure application, we decided to REQUIRE the existence of the claim,
// if an audience is expected. // if an audience is expected.
func WithAudience(aud string) ParserOption { func WithAudience(aud ...string) ParserOption {
return func(p *Parser) { return func(p *Parser) {
p.validator.expectedAud = aud p.validator.expectedAud = aud
} }
} }
// WithAllAudiences configures the validator to require all the specified
// audiences in the `aud` claim. Validation will fail if the specified audiences
// are not listed in the token or the `aud` claim is missing. Duplicates within
// the list are de-duplicated since internally, we use a map to look up the
// audiences.
//
// NOTE: While the `aud` claim is OPTIONAL in a JWT, the handling of it is
// application-specific. Since this validation API is helping developers in
// writing secure application, we decided to REQUIRE the existence of the claim,
// if an audience is expected.
func WithAllAudiences(aud ...string) ParserOption {
return func(p *Parser) {
p.validator.expectedAud = aud
p.validator.expectAllAud = true
}
}
// WithIssuer configures the validator to require the specified issuer in the // WithIssuer configures the validator to require the specified issuer in the
// `iss` claim. Validation will fail if a different issuer is specified in the // `iss` claim. Validation will fail if a different issuer is specified in the
// token or the `iss` claim is missing. // token or the `iss` claim is missing.

View file

@ -46,7 +46,7 @@ func (m *SigningMethodRSA) Alg() string {
// Verify implements token verification for the SigningMethod // Verify implements token verification for the SigningMethod
// For this signing method, must be an *rsa.PublicKey structure. // For this signing method, must be an *rsa.PublicKey structure.
func (m *SigningMethodRSA) Verify(signingString string, sig []byte, key interface{}) error { func (m *SigningMethodRSA) Verify(signingString string, sig []byte, key any) error {
var rsaKey *rsa.PublicKey var rsaKey *rsa.PublicKey
var ok bool var ok bool
@ -67,7 +67,7 @@ func (m *SigningMethodRSA) Verify(signingString string, sig []byte, key interfac
// Sign implements token signing for the SigningMethod // Sign implements token signing for the SigningMethod
// For this signing method, must be an *rsa.PrivateKey structure. // For this signing method, must be an *rsa.PrivateKey structure.
func (m *SigningMethodRSA) Sign(signingString string, key interface{}) ([]byte, error) { func (m *SigningMethodRSA) Sign(signingString string, key any) ([]byte, error) {
var rsaKey *rsa.PrivateKey var rsaKey *rsa.PrivateKey
var ok bool var ok bool

View file

@ -1,6 +1,3 @@
//go:build go1.4
// +build go1.4
package jwt package jwt
import ( import (
@ -82,7 +79,7 @@ func init() {
// Verify implements token verification for the SigningMethod. // Verify implements token verification for the SigningMethod.
// For this verify method, key must be an rsa.PublicKey struct // For this verify method, key must be an rsa.PublicKey struct
func (m *SigningMethodRSAPSS) Verify(signingString string, sig []byte, key interface{}) error { func (m *SigningMethodRSAPSS) Verify(signingString string, sig []byte, key any) error {
var rsaKey *rsa.PublicKey var rsaKey *rsa.PublicKey
switch k := key.(type) { switch k := key.(type) {
case *rsa.PublicKey: case *rsa.PublicKey:
@ -108,7 +105,7 @@ func (m *SigningMethodRSAPSS) Verify(signingString string, sig []byte, key inter
// Sign implements token signing for the SigningMethod. // Sign implements token signing for the SigningMethod.
// For this signing method, key must be an rsa.PrivateKey struct // For this signing method, key must be an rsa.PrivateKey struct
func (m *SigningMethodRSAPSS) Sign(signingString string, key interface{}) ([]byte, error) { func (m *SigningMethodRSAPSS) Sign(signingString string, key any) ([]byte, error) {
var rsaKey *rsa.PrivateKey var rsaKey *rsa.PrivateKey
switch k := key.(type) { switch k := key.(type) {

View file

@ -23,7 +23,7 @@ func ParseRSAPrivateKeyFromPEM(key []byte) (*rsa.PrivateKey, error) {
return nil, ErrKeyMustBePEMEncoded return nil, ErrKeyMustBePEMEncoded
} }
var parsedKey interface{} var parsedKey any
if parsedKey, err = x509.ParsePKCS1PrivateKey(block.Bytes); err != nil { if parsedKey, err = x509.ParsePKCS1PrivateKey(block.Bytes); err != nil {
if parsedKey, err = x509.ParsePKCS8PrivateKey(block.Bytes); err != nil { if parsedKey, err = x509.ParsePKCS8PrivateKey(block.Bytes); err != nil {
return nil, err return nil, err
@ -53,7 +53,7 @@ func ParseRSAPrivateKeyFromPEMWithPassword(key []byte, password string) (*rsa.Pr
return nil, ErrKeyMustBePEMEncoded return nil, ErrKeyMustBePEMEncoded
} }
var parsedKey interface{} var parsedKey any
var blockDecrypted []byte var blockDecrypted []byte
if blockDecrypted, err = x509.DecryptPEMBlock(block, []byte(password)); err != nil { if blockDecrypted, err = x509.DecryptPEMBlock(block, []byte(password)); err != nil {
@ -86,7 +86,7 @@ func ParseRSAPublicKeyFromPEM(key []byte) (*rsa.PublicKey, error) {
} }
// Parse the key // Parse the key
var parsedKey interface{} var parsedKey any
if parsedKey, err = x509.ParsePKIXPublicKey(block.Bytes); err != nil { if parsedKey, err = x509.ParsePKIXPublicKey(block.Bytes); err != nil {
if cert, err := x509.ParseCertificate(block.Bytes); err == nil { if cert, err := x509.ParseCertificate(block.Bytes); err == nil {
parsedKey = cert.PublicKey parsedKey = cert.PublicKey

View file

@ -12,9 +12,9 @@ var signingMethodLock = new(sync.RWMutex)
// signature in Sign. The signature is then usually base64 encoded as part of a // signature in Sign. The signature is then usually base64 encoded as part of a
// JWT. // JWT.
type SigningMethod interface { type SigningMethod interface {
Verify(signingString string, sig []byte, key interface{}) error // Returns nil if signature is valid Verify(signingString string, sig []byte, key any) error // Returns nil if signature is valid
Sign(signingString string, key interface{}) ([]byte, error) // Returns signature or error Sign(signingString string, key any) ([]byte, error) // Returns signature or error
Alg() string // returns the alg identifier for this method (example: 'HS256') Alg() string // returns the alg identifier for this method (example: 'HS256')
} }
// RegisterSigningMethod registers the "alg" name and a factory function for signing method. // RegisterSigningMethod registers the "alg" name and a factory function for signing method.

View file

@ -11,9 +11,9 @@ import (
// Token. This allows you to use properties in the Header of the token (such as // Token. This allows you to use properties in the Header of the token (such as
// `kid`) to identify which key to use. // `kid`) to identify which key to use.
// //
// The returned interface{} may be a single key or a VerificationKeySet containing // The returned any may be a single key or a VerificationKeySet containing
// multiple keys. // multiple keys.
type Keyfunc func(*Token) (interface{}, error) type Keyfunc func(*Token) (any, error)
// VerificationKey represents a public or secret key for verifying a token's signature. // VerificationKey represents a public or secret key for verifying a token's signature.
type VerificationKey interface { type VerificationKey interface {
@ -28,12 +28,12 @@ type VerificationKeySet struct {
// Token represents a JWT Token. Different fields will be used depending on // Token represents a JWT Token. Different fields will be used depending on
// whether you're creating or parsing/verifying a token. // whether you're creating or parsing/verifying a token.
type Token struct { type Token struct {
Raw string // Raw contains the raw token. Populated when you [Parse] a token Raw string // Raw contains the raw token. Populated when you [Parse] a token
Method SigningMethod // Method is the signing method used or to be used Method SigningMethod // Method is the signing method used or to be used
Header map[string]interface{} // Header is the first segment of the token in decoded form 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 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 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 Valid bool // Valid specifies if the token is valid. Populated when you Parse/Verify a token
} }
// New creates a new [Token] with the specified signing method and an empty map // New creates a new [Token] with the specified signing method and an empty map
@ -46,7 +46,7 @@ func New(method SigningMethod, opts ...TokenOption) *Token {
// claims. Additional options can be specified, but are currently unused. // claims. Additional options can be specified, but are currently unused.
func NewWithClaims(method SigningMethod, claims Claims, opts ...TokenOption) *Token { func NewWithClaims(method SigningMethod, claims Claims, opts ...TokenOption) *Token {
return &Token{ return &Token{
Header: map[string]interface{}{ Header: map[string]any{
"typ": "JWT", "typ": "JWT",
"alg": method.Alg(), "alg": method.Alg(),
}, },
@ -60,7 +60,7 @@ func NewWithClaims(method SigningMethod, claims Claims, opts ...TokenOption) *To
// https://golang-jwt.github.io/jwt/usage/signing_methods/#signing-methods-and-key-types // https://golang-jwt.github.io/jwt/usage/signing_methods/#signing-methods-and-key-types
// for an overview of the different signing methods and their respective key // for an overview of the different signing methods and their respective key
// types. // types.
func (t *Token) SignedString(key interface{}) (string, error) { func (t *Token) SignedString(key any) (string, error) {
sstr, err := t.SigningString() sstr, err := t.SigningString()
if err != nil { if err != nil {
return "", err return "", err

View file

@ -103,7 +103,7 @@ func (date *NumericDate) UnmarshalJSON(b []byte) (err error) {
type ClaimStrings []string type ClaimStrings []string
func (s *ClaimStrings) UnmarshalJSON(data []byte) (err error) { func (s *ClaimStrings) UnmarshalJSON(data []byte) (err error) {
var value interface{} var value any
if err = json.Unmarshal(data, &value); err != nil { if err = json.Unmarshal(data, &value); err != nil {
return err return err
@ -116,7 +116,7 @@ func (s *ClaimStrings) UnmarshalJSON(data []byte) (err error) {
aud = append(aud, v) aud = append(aud, v)
case []string: case []string:
aud = ClaimStrings(v) aud = ClaimStrings(v)
case []interface{}: case []any:
for _, vv := range v { for _, vv := range v {
vs, ok := vv.(string) vs, ok := vv.(string)
if !ok { if !ok {

View file

@ -1,8 +1,8 @@
package jwt package jwt
import ( import (
"crypto/subtle"
"fmt" "fmt"
"slices"
"time" "time"
) )
@ -52,8 +52,12 @@ type Validator struct {
verifyIat bool verifyIat bool
// expectedAud contains the audience this token expects. Supplying an empty // expectedAud contains the audience this token expects. Supplying an empty
// string will disable aud checking. // slice will disable aud checking.
expectedAud string expectedAud []string
// expectAllAud specifies whether all expected audiences must be present in
// the token. If false, only one of the expected audiences must be present.
expectAllAud bool
// expectedIss contains the issuer this token expects. Supplying an empty // expectedIss contains the issuer this token expects. Supplying an empty
// string will disable iss checking. // string will disable iss checking.
@ -88,7 +92,7 @@ func NewValidator(opts ...ParserOption) *Validator {
func (v *Validator) Validate(claims Claims) error { func (v *Validator) Validate(claims Claims) error {
var ( var (
now time.Time now time.Time
errs []error = make([]error, 0, 6) errs = make([]error, 0, 6)
err error err error
) )
@ -120,8 +124,8 @@ func (v *Validator) Validate(claims Claims) error {
} }
// If we have an expected audience, we also require the audience claim // If we have an expected audience, we also require the audience claim
if v.expectedAud != "" { if len(v.expectedAud) > 0 {
if err = v.verifyAudience(claims, v.expectedAud, true); err != nil { if err = v.verifyAudience(claims, v.expectedAud, v.expectAllAud); err != nil {
errs = append(errs, err) errs = append(errs, err)
} }
} }
@ -226,33 +230,39 @@ func (v *Validator) verifyNotBefore(claims Claims, cmp time.Time, required bool)
// //
// Additionally, if any error occurs while retrieving the claim, e.g., when its // Additionally, if any error occurs while retrieving the claim, e.g., when its
// the wrong type, an ErrTokenUnverifiable error will be returned. // the wrong type, an ErrTokenUnverifiable error will be returned.
func (v *Validator) verifyAudience(claims Claims, cmp string, required bool) error { func (v *Validator) verifyAudience(claims Claims, cmp []string, expectAllAud bool) error {
aud, err := claims.GetAudience() aud, err := claims.GetAudience()
if err != nil { if err != nil {
return err return err
} }
if len(aud) == 0 { // Check that aud exists and is not empty. We only require the aud claim
// if we expect at least one audience to be present.
if len(aud) == 0 || len(aud) == 1 && aud[0] == "" {
required := len(v.expectedAud) > 0
return errorIfRequired(required, "aud") return errorIfRequired(required, "aud")
} }
// use a var here to keep constant time compare when looping over a number of claims if !expectAllAud {
result := false for _, a := range aud {
// If we only expect one match, we can stop early if we find a match
var stringClaims string if slices.Contains(cmp, a) {
for _, a := range aud { return nil
if subtle.ConstantTimeCompare([]byte(a), []byte(cmp)) != 0 { }
result = true
} }
stringClaims = stringClaims + a
return ErrTokenInvalidAudience
} }
// case where "" is sent in one or many aud claims // Note that we are looping cmp here to ensure that all expected audiences
if stringClaims == "" { // are present in the aud claim.
return errorIfRequired(required, "aud") for _, a := range cmp {
if !slices.Contains(aud, a) {
return ErrTokenInvalidAudience
}
} }
return errorIfFalse(result, ErrTokenInvalidAudience) return nil
} }
// verifyIssuer compares the iss claim in claims against cmp. // verifyIssuer compares the iss claim in claims against cmp.

6
vendor/modules.txt vendored
View file

@ -210,7 +210,7 @@ code.superseriousbusiness.org/go-png-image-structure/v2
# code.superseriousbusiness.org/httpsig v1.4.0 # code.superseriousbusiness.org/httpsig v1.4.0
## explicit; go 1.21 ## explicit; go 1.21
code.superseriousbusiness.org/httpsig code.superseriousbusiness.org/httpsig
# code.superseriousbusiness.org/oauth2/v4 v4.5.4-0.20250606121655-9d54ef189d42 # code.superseriousbusiness.org/oauth2/v4 v4.5.4-0.20250812115401-3961e46a7384
## explicit; go 1.23.0 ## explicit; go 1.23.0
code.superseriousbusiness.org/oauth2/v4 code.superseriousbusiness.org/oauth2/v4
code.superseriousbusiness.org/oauth2/v4/errors code.superseriousbusiness.org/oauth2/v4/errors
@ -555,8 +555,8 @@ github.com/goccy/go-json/internal/encoder/vm_color_indent
github.com/goccy/go-json/internal/encoder/vm_indent github.com/goccy/go-json/internal/encoder/vm_indent
github.com/goccy/go-json/internal/errors github.com/goccy/go-json/internal/errors
github.com/goccy/go-json/internal/runtime github.com/goccy/go-json/internal/runtime
# github.com/golang-jwt/jwt/v5 v5.2.2 # github.com/golang-jwt/jwt/v5 v5.3.0
## explicit; go 1.18 ## explicit; go 1.21
github.com/golang-jwt/jwt/v5 github.com/golang-jwt/jwt/v5
# github.com/golang/geo v0.0.0-20200319012246-673a6f80352d # github.com/golang/geo v0.0.0-20200319012246-673a6f80352d
## explicit; go 1.12 ## explicit; go 1.12