1
0
mirror of https://github.com/pocketbase/pocketbase.git synced 2025-02-06 10:44:43 +00:00

upgraded to jwt/v5

This commit is contained in:
Gani Georgiev 2025-01-05 11:05:26 +02:00
parent 41f1ff2b5f
commit b150a3a98a
11 changed files with 43 additions and 33 deletions

View File

@ -2,6 +2,8 @@
- Added JSVM `new Timezone(name)` binding for constructing `time.Location` value ([#6219](https://github.com/pocketbase/pocketbase/discussions/6219)). - Added JSVM `new Timezone(name)` binding for constructing `time.Location` value ([#6219](https://github.com/pocketbase/pocketbase/discussions/6219)).
- Upgraded to `golang-jwt/jwt/v5`.
## v0.24.1 ## v0.24.1

View File

@ -4,7 +4,7 @@ import (
"errors" "errors"
"time" "time"
"github.com/golang-jwt/jwt/v4" "github.com/golang-jwt/jwt/v5"
"github.com/pocketbase/pocketbase/tools/security" "github.com/pocketbase/pocketbase/tools/security"
) )

View File

@ -6,7 +6,7 @@ import (
"time" "time"
validation "github.com/go-ozzo/ozzo-validation/v4" validation "github.com/go-ozzo/ozzo-validation/v4"
"github.com/golang-jwt/jwt/v4" "github.com/golang-jwt/jwt/v5"
"github.com/pocketbase/pocketbase/core" "github.com/pocketbase/pocketbase/core"
) )

View File

@ -9,7 +9,7 @@ import (
"encoding/pem" "encoding/pem"
"testing" "testing"
"github.com/golang-jwt/jwt/v4" "github.com/golang-jwt/jwt/v5"
"github.com/pocketbase/pocketbase/forms" "github.com/pocketbase/pocketbase/forms"
"github.com/pocketbase/pocketbase/tests" "github.com/pocketbase/pocketbase/tests"
) )

2
go.mod
View File

@ -19,7 +19,7 @@ require (
github.com/gabriel-vasile/mimetype v1.4.8 github.com/gabriel-vasile/mimetype v1.4.8
github.com/ganigeorgiev/fexpr v0.4.1 github.com/ganigeorgiev/fexpr v0.4.1
github.com/go-ozzo/ozzo-validation/v4 v4.3.0 github.com/go-ozzo/ozzo-validation/v4 v4.3.0
github.com/golang-jwt/jwt/v4 v4.5.1 github.com/golang-jwt/jwt/v5 v5.2.1
github.com/pocketbase/dbx v1.11.0 github.com/pocketbase/dbx v1.11.0
github.com/pocketbase/tygoja v0.0.0-20250103200817-ca580d8c5119 github.com/pocketbase/tygoja v0.0.0-20250103200817-ca580d8c5119
github.com/spf13/cast v1.7.1 github.com/spf13/cast v1.7.1

4
go.sum
View File

@ -113,8 +113,8 @@ github.com/go-sourcemap/sourcemap v2.1.4+incompatible/go.mod h1:F8jJfvm2KbVjc5Nq
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo= github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ= github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=

View File

@ -18,7 +18,7 @@ import (
"github.com/dop251/goja" "github.com/dop251/goja"
validation "github.com/go-ozzo/ozzo-validation/v4" validation "github.com/go-ozzo/ozzo-validation/v4"
"github.com/golang-jwt/jwt/v4" "github.com/golang-jwt/jwt/v5"
"github.com/pocketbase/dbx" "github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase/apis" "github.com/pocketbase/pocketbase/apis"
"github.com/pocketbase/pocketbase/core" "github.com/pocketbase/pocketbase/core"

View File

@ -6,7 +6,7 @@ import (
"errors" "errors"
"strings" "strings"
"github.com/golang-jwt/jwt/v4" "github.com/golang-jwt/jwt/v5"
"github.com/pocketbase/pocketbase/tools/types" "github.com/pocketbase/pocketbase/tools/types"
"github.com/spf13/cast" "github.com/spf13/cast"
"golang.org/x/oauth2" "golang.org/x/oauth2"
@ -138,19 +138,17 @@ func (p *Apple) parseAndVerifyIdToken(idToken string) (jwt.MapClaims, error) {
// validate common claims per https://developer.apple.com/documentation/sign_in_with_apple/sign_in_with_apple_rest_api/verifying_a_user#3383769 // validate common claims per https://developer.apple.com/documentation/sign_in_with_apple/sign_in_with_apple_rest_api/verifying_a_user#3383769
// --- // ---
err = claims.Valid() // exp, iat, etc. jwtValidator := jwt.NewValidator(
jwt.WithExpirationRequired(),
jwt.WithIssuedAt(),
jwt.WithIssuer("https://appleid.apple.com"),
jwt.WithAudience(p.clientId),
)
err = jwtValidator.Validate(claims)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if !claims.VerifyIssuer("https://appleid.apple.com", true) {
return nil, errors.New("iss must be https://appleid.apple.com")
}
if !claims.VerifyAudience(p.clientId, true) {
return nil, errors.New("aud must be the developer's client_id")
}
// validate id_token signature // validate id_token signature
// //
// note: this step could be technically considered optional because we trust // note: this step could be technically considered optional because we trust

View File

@ -12,7 +12,8 @@ import (
"net/http" "net/http"
"strings" "strings"
"github.com/golang-jwt/jwt/v4" "github.com/golang-jwt/jwt/v5"
"github.com/pocketbase/pocketbase/tools/security"
"github.com/pocketbase/pocketbase/tools/types" "github.com/pocketbase/pocketbase/tools/types"
"github.com/spf13/cast" "github.com/spf13/cast"
"golang.org/x/oauth2" "golang.org/x/oauth2"
@ -128,24 +129,24 @@ func (p *OIDC) parseIdToken(token *oauth2.Token) (jwt.MapClaims, error) {
return nil, err return nil, err
} }
// validate common claims like exp, iat, etc. // validate common claims
err = claims.Valid() jwtValidator := jwt.NewValidator(
jwt.WithIssuedAt(),
jwt.WithAudience(p.clientId),
)
err = jwtValidator.Validate(claims)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// validate aud
if !claims.VerifyAudience(p.clientId, true) {
return nil, errors.New("aud must be the developer's client_id")
}
// validate iss (if "issuers" extra config is set) // validate iss (if "issuers" extra config is set)
issuers := cast.ToStringSlice(p.Extra()["issuers"]) issuers := cast.ToStringSlice(p.Extra()["issuers"])
if len(issuers) > 0 { if len(issuers) > 0 {
var isIssValid bool var isIssValid bool
claimIssuer, _ := claims.GetIssuer()
for _, issuer := range issuers { for _, issuer := range issuers {
if claims.VerifyIssuer(issuer, true) { if security.Equal(claimIssuer, issuer) {
isIssValid = true isIssValid = true
break break
} }

View File

@ -4,8 +4,7 @@ import (
"errors" "errors"
"time" "time"
// @todo update to v5 "github.com/golang-jwt/jwt/v5"
"github.com/golang-jwt/jwt/v4"
) )
// ParseUnverifiedJWT parses JWT and returns its claims // ParseUnverifiedJWT parses JWT and returns its claims
@ -19,7 +18,7 @@ func ParseUnverifiedJWT(token string) (jwt.MapClaims, error) {
_, _, err := parser.ParseUnverified(token, claims) _, _, err := parser.ParseUnverified(token, claims)
if err == nil { if err == nil {
err = claims.Valid() err = jwt.NewValidator(jwt.WithIssuedAt()).Validate(claims)
} }
return claims, err return claims, err

View File

@ -6,7 +6,7 @@ import (
"testing" "testing"
"time" "time"
"github.com/golang-jwt/jwt/v4" "github.com/golang-jwt/jwt/v5"
"github.com/pocketbase/pocketbase/tools/security" "github.com/pocketbase/pocketbase/tools/security"
) )
@ -21,7 +21,7 @@ func TestParseUnverifiedJWT(t *testing.T) {
} }
// properly formatted JWT with INVALID claims // properly formatted JWT with INVALID claims
// {"name": "test", "exp": 1516239022} // {"name": "test", "exp":1516239022}
result2, err2 := security.ParseUnverifiedJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoidGVzdCIsImV4cCI6MTUxNjIzOTAyMn0.xYHirwESfSEW3Cq2BL47CEASvD_p_ps3QCA54XtNktU") result2, err2 := security.ParseUnverifiedJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoidGVzdCIsImV4cCI6MTUxNjIzOTAyMn0.xYHirwESfSEW3Cq2BL47CEASvD_p_ps3QCA54XtNktU")
if err2 == nil { if err2 == nil {
t.Error("Expected error got nil") t.Error("Expected error got nil")
@ -30,14 +30,24 @@ func TestParseUnverifiedJWT(t *testing.T) {
t.Errorf("Expected to have 2 claims, got %v", result2) t.Errorf("Expected to have 2 claims, got %v", result2)
} }
// properly formatted JWT with VALID claims // properly formatted JWT with VALID claims (missing exp)
// {"name": "test"} // {"name": "test"}
result3, err3 := security.ParseUnverifiedJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoidGVzdCJ9.ml0QsTms3K9wMygTu41ZhKlTyjmW9zHQtoS8FUsCCjU") result3, err3 := security.ParseUnverifiedJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoidGVzdCJ9.ml0QsTms3K9wMygTu41ZhKlTyjmW9zHQtoS8FUsCCjU")
if err3 != nil { if err3 != nil {
t.Error("Expected nil, got", err3) t.Error("Expected nil, got", err3)
} }
if len(result3) != 1 || result3["name"] != "test" { if len(result3) != 1 || result3["name"] != "test" {
t.Errorf("Expected to have 2 claims, got %v", result3) t.Errorf("Expected to have 1 claim, got %v", result3)
}
// properly formatted JWT with VALID claims (valid exp)
// {"name": "test", "exp": 2208985261}
result4, err4 := security.ParseUnverifiedJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoidGVzdCIsImV4cCI6MjIwODk4NTI2MX0._0KQu60hYNx5wkBIpEaoX35shXRicb0X_0VdWKWb-3k")
if err4 != nil {
t.Error("Expected nil, got", err4)
}
if len(result4) != 2 || result4["name"] != "test" {
t.Errorf("Expected to have 2 claims, got %v", result4)
} }
} }