diff --git a/api-reference/apis/admin-api/authentication-and-security.md b/api-reference/apis/admin-api/authentication-and-security.md index 35920e6..c4c878b 100644 --- a/api-reference/apis/admin-api/authentication-and-security.md +++ b/api-reference/apis/admin-api/authentication-and-security.md @@ -33,10 +33,10 @@ import ( "os" "time" - "github.com/lestrrat-go/jwx/v2/jwa" - "github.com/lestrrat-go/jwx/v2/jwk" - "github.com/lestrrat-go/jwx/v2/jws" - "github.com/lestrrat-go/jwx/v2/jwt" + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jwk" + "github.com/lestrrat-go/jwx/v3/jws" + "github.com/lestrrat-go/jwx/v3/jwt" ) // Replace "myapp" with your project ID here. @@ -68,7 +68,7 @@ func main() { _ = payload.Set(jwt.ExpirationKey, now.Add(5*time.Minute).Unix()) // The alg MUST be RS256. - alg := jwa.RS256 + alg := jwa.RS256() hdr := jws.NewHeaders() hdr.Set("typ", "JWT") diff --git a/authentication-and-access/authentication/reauthentication.md b/authentication-and-access/authentication/reauthentication.md index 4738779..3a24c7f 100644 --- a/authentication-and-access/authentication/reauthentication.md +++ b/authentication-and-access/authentication/reauthentication.md @@ -503,8 +503,8 @@ import ( "net/http" "time" - "github.com/lestrrat-go/jwx/jwk" - "github.com/lestrrat-go/jwx/jwt" + "github.com/lestrrat-go/jwx/v3/jwk" + "github.com/lestrrat-go/jwx/v3/jwt" ) var ( @@ -558,7 +558,13 @@ func CheckIDToken(idToken string) error { } // parse jwt token - token, err := jwt.ParseString(idToken, jwt.WithKeySet(set)) + token, err := jwt.ParseString( + idToken, + // This may not work out of the box depending on the jwk.Set. + // Please read about requirements for "kid" and "alg" (and possibly + // "WithDefaultKey") when using jwk.Set in the jwt.WithKeySet documentation. + jwt.WithKeySet(set), + ) if err != nil { return fmt.Errorf("invalid token: %s", err) } @@ -574,14 +580,9 @@ func CheckIDToken(idToken string) error { return fmt.Errorf("invalid token: %s", err) } - authTimeAny, ok := token.Get("auth_time") - if !ok { - return fmt.Errorf("no auth_time") - } - - authTimeUnix, ok := authTimeAny.(float64) - if !ok { - return fmt.Errorf("auth_time is not number") + var authTimeUnix float64 + if err := token.Get("auth_time", &authTimeUnix); err != nil { + return fmt.Errorf("no auth_time: %w", err) } authTime := time.Unix(int64(authTimeUnix), 0) diff --git a/get-started/backend-api/jwt.md b/get-started/backend-api/jwt.md index f1cbf6e..d56b957 100644 --- a/get-started/backend-api/jwt.md +++ b/get-started/backend-api/jwt.md @@ -273,8 +273,8 @@ import ( "regexp" "time" - "github.com/lestrrat-go/jwx/jwk" - "github.com/lestrrat-go/jwx/jwt" + "github.com/lestrrat-go/jwx/v3/jwk" + "github.com/lestrrat-go/jwx/v3/jwt" ) @@ -322,25 +322,24 @@ func FetchJWK(baseAddress string) (jwk.Set, error) { } // DecodeUser parse request Authorization header and obtain user id and claims -func DecodeUser(r *http.Request) (string, map[string]interface{}, error) { +func DecodeUser(r *http.Request) (string, bool, bool, error) // fetch jwks_uri from Authgear - // you can cache the value of jwks to have better performance + // you can cache the value of jwks using jwk.Cache to have better performance set, err := FetchJWK(baseAddress) if err != nil { - return "", nil, fmt.Errorf("failed to fetch JWK: %s", err) - } - - // get jwt token from Authorization header - authzHeader := r.Header.Get("Authorization") - match := authzHeaderRegexp.FindStringSubmatch(authzHeader) - if len(match) != 2 { - return "", nil, fmt.Errorf("no token") + return "", false, false, fmt.Errorf("failed to fetch JWK: %s", err) } // parse jwt token - token, err := jwt.ParseString(match[1], jwt.WithKeySet(set)) + token, err := jwt.ParseRequest( + r, + // This may not work out of the box depending on the jwk.Set. + // Please read about requirements for "kid" and "alg" (and possibly + // "WithDefaultKey") when using jwk.Set in the jwt.WithKeySet documentation. + jwt.WithKeySet(set), + ) if err != nil { - return "", nil, fmt.Errorf("invalid token: %s", err) + return "", false, false, fmt.Errorf("invalid token: %s", err) } // validate jwt token @@ -351,19 +350,21 @@ func DecodeUser(r *http.Request) (string, map[string]interface{}, error) { jwt.WithAudience(baseAddress), ) if err != nil { - return "", nil, fmt.Errorf("invalid token: %s", err) + return "", false, false, fmt.Errorf("invalid token: %s", err) } - return token.Subject(), token.PrivateClaims(), nil + var verified bool + var anonymous bool + // ignore errors -- if the the claim does not exist, it doesn't matter + _ = token.Get("https://authgear.com/claims/user/is_verified", &verified) + _ = token.Get("https://authgear.com/claims/user/is_anonymous", &anonymous) + + return token.Subject(), verified, anonymous, nil } func handler(w http.ResponseWriter, r *http.Request) { // decode user example - userid, claims, err := DecodeUser(r) - isUserVerified, _ := - claims["https://authgear.com/claims/user/is_verified"].(bool) - isAnonymousUser, _ := - claims["https://authgear.com/claims/user/is_anonymous"].(bool) + userid, isUserVerified, isAnonymousUser, err := DecodeUser(r) // ... your handler logic }