Repository: hyperledger/aries-framework-go
Pull request #3563 (2023-04-22 12:15:23)

perf: improve parsing operations performance

codecov[bot]: ## [Codecov](https://codecov.io/gh/hyperledger/aries-framework-go/pull/3563?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperledger) Report
> Merging [#3563](https://codecov.io/gh/hyperledger/aries-framework-go/pull/3563?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperledger) (fd3f841) into [main](https://codecov.io/gh/hyperledger/aries-framework-go/commit/7798567c6ed1308569d118b82bbb9cd236e392f3?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperledger) (7798567) will **increase** coverage by `0.00%`.
> The diff coverage is `88.57%`.

```diff
@@           Coverage Diff           @@
##             main    #3563   +/-   ##
=======================================
  Coverage   87.75%   87.76%           
=======================================
  Files         351      351           
  Lines       48646    48631   -15     
=======================================
- Hits        42690    42681    -9     
+ Misses       4406     4402    -4     
+ Partials     1550     1548    -2     
```


| [Impacted Files](https://codecov.io/gh/hyperledger/aries-framework-go/pull/3563?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperledger) | Coverage Δ | |
|---|---|---|
| [pkg/doc/sdjwt/verifier/verifier.go](https://codecov.io/gh/hyperledger/aries-framework-go/pull/3563?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperledger#diff-cGtnL2RvYy9zZGp3dC92ZXJpZmllci92ZXJpZmllci5nbw==) | `90.86% <69.23%> (+0.24%)` | :arrow_up: |
| [pkg/doc/didconfig/didconfig.go](https://codecov.io/gh/hyperledger/aries-framework-go/pull/3563?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperledger#diff-cGtnL2RvYy9kaWRjb25maWcvZGlkY29uZmlnLmdv) | `95.57% <100.00%> (ø)` | |
| [pkg/doc/jwt/jwt.go](https://codecov.io/gh/hyperledger/aries-framework-go/pull/3563?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperledger#diff-cGtnL2RvYy9qd3Qvand0Lmdv) | `98.30% <100.00%> (+0.06%)` | :arrow_up: |
| [pkg/doc/jwt/jwt\_support.go](https://codecov.io/gh/hyperledger/aries-framework-go/pull/3563?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperledger#diff-cGtnL2RvYy9qd3Qvand0X3N1cHBvcnQuZ28=) | `62.85% <100.00%> (ø)` | |
| [pkg/doc/presexch/definition.go](https://codecov.io/gh/hyperledger/aries-framework-go/pull/3563?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperledger#diff-cGtnL2RvYy9wcmVzZXhjaC9kZWZpbml0aW9uLmdv) | `85.32% <100.00%> (ø)` | |
| [pkg/doc/sdjwt/common/common.go](https://codecov.io/gh/hyperledger/aries-framework-go/pull/3563?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperledger#diff-cGtnL2RvYy9zZGp3dC9jb21tb24vY29tbW9uLmdv) | `94.17% <100.00%> (+0.69%)` | :arrow_up: |
| [pkg/doc/sdjwt/holder/holder.go](https://codecov.io/gh/hyperledger/aries-framework-go/pull/3563?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperledger#diff-cGtnL2RvYy9zZGp3dC9ob2xkZXIvaG9sZGVyLmdv) | `100.00% <100.00%> (ø)` | |
| [pkg/doc/sdjwt/issuer/issuer.go](https://codecov.io/gh/hyperledger/aries-framework-go/pull/3563?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperledger#diff-cGtnL2RvYy9zZGp3dC9pc3N1ZXIvaXNzdWVyLmdv) | `92.99% <100.00%> (+1.04%)` | :arrow_up: |
| [pkg/doc/signature/jsonld/processor.go](https://codecov.io/gh/hyperledger/aries-framework-go/pull/3563?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperledger#diff-cGtnL2RvYy9zaWduYXR1cmUvanNvbmxkL3Byb2Nlc3Nvci5nbw==) | `70.66% <100.00%> (-0.99%)` | :arrow_down: |
| [pkg/doc/util/didsignjwt/signjwt.go](https://codecov.io/gh/hyperledger/aries-framework-go/pull/3563?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperledger#diff-cGtnL2RvYy91dGlsL2RpZHNpZ25qd3Qvc2lnbmp3dC5nbw==) | `86.88% <100.00%> (ø)` | |
| ... and [2 more](https://codecov.io/gh/hyperledger/aries-framework-go/pull/3563?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperledger) | |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperledger). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperledger)


Patch:
diff --git a/pkg/common/utils/map.go b/pkg/common/utils/map.go
new file mode 100644
index 00000000..5e4ddb07
--- /dev/null
+++ b/pkg/common/utils/map.go
@@ -0,0 +1,23 @@
+/*
+Copyright SecureKey Technologies Inc. All Rights Reserved.
+
+SPDX-License-Identifier: Apache-2.0
+*/
+
+package utils
+
+// CopyMap performs shallow copy of map and nested maps.
+func CopyMap(m map[string]interface{}) map[string]interface{} {
+	cm := make(map[string]interface{})
+
+	for k, v := range m {
+		vm, ok := v.(map[string]interface{})
+		if ok {
+			cm[k] = CopyMap(vm)
+		} else {
+			cm[k] = v
+		}
+	}
+
+	return cm
+}
diff --git a/pkg/common/utils/mapstruct.go b/pkg/common/utils/mapstruct.go
new file mode 100644
index 00000000..75a29ee1
--- /dev/null
+++ b/pkg/common/utils/mapstruct.go
@@ -0,0 +1,44 @@
+/*
+Copyright SecureKey Technologies Inc. All Rights Reserved.
+
+SPDX-License-Identifier: Apache-2.0
+*/
+
+package utils
+
+import (
+	"fmt"
+	"reflect"
+	"strconv"
+	"strings"
+	"time"
+
+	"github.com/go-jose/go-jose/v3/jwt"
+	"github.com/mitchellh/mapstructure"
+)
+
+// JSONNumberToJwtNumericDate hook for mapstructure library to decode json.Number to jwt.NumericDate.
+func JSONNumberToJwtNumericDate() mapstructure.DecodeHookFuncType {
+	return func(
+		f reflect.Type,
+		t reflect.Type,
+		data interface{},
+	) (interface{}, error) {
+		if f.String() != "json.Number" || !strings.Contains("jwt.NumericDate", t.String()) {
+			return data, nil
+		}
+
+		parsedFloat, err := strconv.ParseFloat(fmt.Sprint(data), 64)
+		if err != nil {
+			return nil, err
+		}
+
+		date := jwt.NewNumericDate(time.Unix(int64(parsedFloat), 0))
+
+		if t.String() == "jwt.NumericDate" {
+			return date, nil
+		}
+
+		return &date, nil
+	}
+}
diff --git a/pkg/doc/didconfig/didconfig.go b/pkg/doc/didconfig/didconfig.go
index c3e342f4..e793460c 100644
--- a/pkg/doc/didconfig/didconfig.go
+++ b/pkg/doc/didconfig/didconfig.go
@@ -209,7 +209,7 @@ func validateDomainLinkageCredential(vc *verifiable.Credential, did, origin stri
 }
 
 func validateJWT(vc *verifiable.Credential, did, origin string) error {
-	jsonWebToken, err := jwt.Parse(vc.JWT, jwt.WithSignatureVerifier(&noVerifier{}))
+	jsonWebToken, _, err := jwt.Parse(vc.JWT, jwt.WithSignatureVerifier(&noVerifier{}))
 	if err != nil {
 		return fmt.Errorf("parse JWT: %w", err)
 	}
diff --git a/pkg/doc/jwt/jwt.go b/pkg/doc/jwt/jwt.go
index 065204ba..80f71a3c 100644
--- a/pkg/doc/jwt/jwt.go
+++ b/pkg/doc/jwt/jwt.go
@@ -33,8 +33,9 @@ type Claims jwt.Claims
 
 // jwtParseOpts holds options for the JWT parsing.
 type parseOpts struct {
-	detachedPayload []byte
-	sigVerifier     jose.SignatureVerifier
+	detachedPayload         []byte
+	sigVerifier             jose.SignatureVerifier
+	ignoreClaimsMapDecoding bool
 }
 
 // ParseOpt is the JWT Parser option.
@@ -47,6 +48,14 @@ func WithJWTDetachedPayload(payload []byte) ParseOpt {
 	}
 }
 
+// WithIgnoreClaimsMapDecoding option is for ignore decoding claims into .Payload map[string]interface.
+// Decoding to map[string]interface is pretty expensive, so this option can be used for performance critical operations.
+func WithIgnoreClaimsMapDecoding(ignoreClaimsMapDecoding bool) ParseOpt {
+	return func(opts *parseOpts) {
+		opts.ignoreClaimsMapDecoding = ignoreClaimsMapDecoding
+	}
+}
+
 // WithSignatureVerifier option is for definition of JWT detached payload.
 func WithSignatureVerifier(signatureVerifier jose.SignatureVerifier) ParseOpt {
 	return func(opts *parseOpts) {
@@ -105,9 +114,9 @@ type JSONWebToken struct {
 
 // Parse parses input JWT in serialized form into JSON Web Token.
 // Currently JWS and unsecured JWT is supported.
-func Parse(jwtSerialized string, opts ...ParseOpt) (*JSONWebToken, error) {
+func Parse(jwtSerialized string, opts ...ParseOpt) (*JSONWebToken, []byte, error) {
 	if !jose.IsCompactJWS(jwtSerialized) {
-		return nil, errors.New("JWT of compacted JWS form is supported only")
+		return nil, nil, errors.New("JWT of compacted JWS form is supported only")
 	}
 
 	pOpts := &parseOpts{}
@@ -149,7 +158,7 @@ func (j *JSONWebToken) Serialize(detached bool) (string, error) {
 	return j.jws.SerializeCompact(detached)
 }
 
-func parseJWS(jwtSerialized string, opts *parseOpts) (*JSONWebToken, error) {
+func parseJWS(jwtSerialized string, opts *parseOpts) (*JSONWebToken, []byte, error) {
 	jwsOpts := make([]jose.JWSParseOpt, 0)
 
 	if opts.detachedPayload != nil {
@@ -158,30 +167,35 @@ func parseJWS(jwtSerialized string, opts *parseOpts) (*JSONWebToken, error) {
 
 	jws, err := jose.ParseJWS(jwtSerialized, opts.sigVerifier, jwsOpts...)
 	if err != nil {
-		return nil, fmt.Errorf("parse JWT from compact JWS: %w", err)
+		return nil, nil, fmt.Errorf("parse JWT from compact JWS: %w", err)
 	}
 
-	return mapJWSToJWT(jws)
+	return mapJWSToJWT(jws, opts)
 }
 
-func mapJWSToJWT(jws *jose.JSONWebSignature) (*JSONWebToken, error) {
+func mapJWSToJWT(jws *jose.JSONWebSignature, opts *parseOpts) (*JSONWebToken, []byte, error) {
 	headers := jws.ProtectedHeaders
 
 	err := checkHeaders(headers)
 	if err != nil {
-		return nil, fmt.Errorf("check JWT headers: %w", err)
+		return nil, nil, fmt.Errorf("check JWT headers: %w", err)
 	}
 
-	claims, err := PayloadToMap(jws.Payload)
-	if err != nil {
-		return nil, fmt.Errorf("read JWT claims from JWS payload: %w", err)
-	}
-
-	return &JSONWebToken{
+	token := &JSONWebToken{
 		Headers: headers,
-		Payload: claims,
 		jws:     jws,
-	}, nil
+	}
+
+	if !opts.ignoreClaimsMapDecoding {
+		claims, err := PayloadToMap(jws.Payload)
+		if err != nil {
+			return nil, nil, fmt.Errorf("read JWT claims from JWS payload: %w", err)
+		}
+
+		token.Payload = claims
+	}
+
+	return token, jws.Payload, nil
 }
 
 // NewSigned creates new signed JSON Web Token based on input claims.
diff --git a/pkg/doc/jwt/jwt_support.go b/pkg/doc/jwt/jwt_support.go
index a8fcadf6..f3e001d3 100644
--- a/pkg/doc/jwt/jwt_support.go
+++ b/pkg/doc/jwt/jwt_support.go
@@ -149,7 +149,7 @@ func verifyEd25519(jws string, pubKey ed25519.PublicKey) error {
 		Verifier: v,
 	})
 
-	token, err := Parse(jws, WithSignatureVerifier(sVerifier))
+	token, _, err := Parse(jws, WithSignatureVerifier(sVerifier))
 	if err != nil {
 		return err
 	}
@@ -169,7 +169,7 @@ func verifyRS256(jws string, pubKey *rsa.PublicKey) error {
 		Verifier: v,
 	})
 
-	token, err := Parse(jws, WithSignatureVerifier(sVerifier))
+	token, _, err := Parse(jws, WithSignatureVerifier(sVerifier))
 	if err != nil {
 		return err
 	}
diff --git a/pkg/doc/presexch/definition.go b/pkg/doc/presexch/definition.go
index 6a0920a6..0e970128 100644
--- a/pkg/doc/presexch/definition.go
+++ b/pkg/doc/presexch/definition.go
@@ -1388,7 +1388,7 @@ func filterFormat(format *Format, credentials []*verifiable.Credential) (string,
 		)
 
 		if credential.JWT != "" {
-			pJWT, err := jwt.Parse(credential.JWT, jwt.WithSignatureVerifier(&noVerifier{}))
+			pJWT, _, err := jwt.Parse(credential.JWT, jwt.WithSignatureVerifier(&noVerifier{}))
 			if err != nil {
 				logger.Warnf("unmarshal credential error: %w", err)
 
diff --git a/pkg/doc/sdjwt/common/common.go b/pkg/doc/sdjwt/common/common.go
index 9d6d54d3..5659e2ec 100644
--- a/pkg/doc/sdjwt/common/common.go
+++ b/pkg/doc/sdjwt/common/common.go
@@ -11,8 +11,10 @@ import (
 	"encoding/base64"
 	"encoding/json"
 	"fmt"
+	"reflect"
 	"strings"
 
+	"github.com/hyperledger/aries-framework-go/pkg/common/utils"
 	afgjwt "github.com/hyperledger/aries-framework-go/pkg/doc/jwt"
 )
 
@@ -177,12 +179,7 @@ func GetHash(hash crypto.Hash, value string) (string, error) {
 
 // VerifyDisclosuresInSDJWT checks for disclosure inclusion in SD-JWT.
 func VerifyDisclosuresInSDJWT(disclosures []string, signedJWT *afgjwt.JSONWebToken) error {
-	var claims map[string]interface{}
-
-	err := signedJWT.DecodeClaims(&claims)
-	if err != nil {
-		return err
-	}
+	claims := utils.CopyMap(signedJWT.Payload)
 
 	// check that the _sd_alg claim is present
 	// check that _sd_alg value is understood and the hash algorithm is deemed secure.
@@ -354,7 +351,7 @@ func GetDisclosedClaims(disclosureClaims []*DisclosureClaim, claims map[string]i
 		return nil, fmt.Errorf("failed to get crypto hash from claims: %w", err)
 	}
 
-	output := copyMap(claims)
+	output := utils.CopyMap(claims)
 	includedDigests := make(map[string]bool)
 
 	err = processDisclosedClaims(disclosureClaims, output, includedDigests, hash)
@@ -445,22 +442,26 @@ func stringArray(entry interface{}) ([]string, error) {
 		return nil, nil
 	}
 
-	entries, ok := entry.([]interface{})
-	if !ok {
+	sliceValue := reflect.ValueOf(entry)
+	if sliceValue.Kind() != reflect.Slice {
 		return nil, fmt.Errorf("entry type[%T] is not an array", entry)
 	}
 
-	var result []string
+	// Iterate over the slice and convert each element to a string
+	stringSlice := make([]string, sliceValue.Len())
+
+	for i := 0; i < sliceValue.Len(); i++ {
+		sliceVal := sliceValue.Index(i).Interface()
+		val, ok := sliceVal.(string)
 
-	for _, e := range entries {
-		if eStr, ok := e.(string); ok {
-			result = append(result, eStr)
-		} else {
-			return nil, fmt.Errorf("entry item type[%T] is not a string", e)
+		if !ok {
+			return nil, fmt.Errorf("entry item type[%T] is not a string", sliceVal)
 		}
+
+		stringSlice[i] = val
 	}
 
-	return result, nil
+	return stringSlice, nil
 }
 
 // SliceToMap converts slice to map.
@@ -474,21 +475,6 @@ func SliceToMap(ids []string) map[string]bool {
 	return values
 }
 
-func copyMap(m map[string]interface{}) map[string]interface{} {
-	cm := make(map[string]interface{})
-
-	for k, v := range m {
-		vm, ok := v.(map[string]interface{})
-		if ok {
-			cm[k] = copyMap(vm)
-		} else {
-			cm[k] = v
-		}
-	}
-
-	return cm
-}
-
 // KeyExistsInMap checks if key exists in map.
 func KeyExistsInMap(key string, m map[string]interface{}) bool {
 	for k, v := range m {
diff --git a/pkg/doc/sdjwt/holder/holder.go b/pkg/doc/sdjwt/holder/holder.go
index 0d94f46c..3e42ec6f 100644
--- a/pkg/doc/sdjwt/holder/holder.go
+++ b/pkg/doc/sdjwt/holder/holder.go
@@ -78,7 +78,7 @@ func Parse(combinedFormatForIssuance string, opts ...ParseOpt) ([]*Claim, error)
 
 	cfi := common.ParseCombinedFormatForIssuance(combinedFormatForIssuance)
 
-	signedJWT, err := afgjwt.Parse(cfi.SDJWT, jwtOpts...)
+	signedJWT, _, err := afgjwt.Parse(cfi.SDJWT, jwtOpts...)
 	if err != nil {
 		return nil, err
 	}
diff --git a/pkg/doc/sdjwt/issuer/issuer.go b/pkg/doc/sdjwt/issuer/issuer.go
index 6ae847d5..ebeec3d5 100644
--- a/pkg/doc/sdjwt/issuer/issuer.go
+++ b/pkg/doc/sdjwt/issuer/issuer.go
@@ -53,6 +53,7 @@ import (
 
 	"github.com/go-jose/go-jose/v3/jwt"
 
+	"github.com/hyperledger/aries-framework-go/pkg/common/utils"
 	"github.com/hyperledger/aries-framework-go/pkg/doc/jose"
 	"github.com/hyperledger/aries-framework-go/pkg/doc/jose/jwk"
 	afgjwt "github.com/hyperledger/aries-framework-go/pkg/doc/jwt"
@@ -224,6 +225,7 @@ func WithNonSelectivelyDisclosableClaims(nonSDClaims []string) NewOpt {
 // New creates new signed Selective Disclosure JWT based on input claims.
 // The Issuer MUST create a Disclosure for each selectively disclosable claim as follows:
 // Create an array of three elements in this order:
+//
 //	A salt value. Generated by the system, the salt value MUST be unique for each claim that is to be selectively
 //	disclosed.
 //	The claim name, or key, as it would be used in a regular JWT body. This MUST be a string.
@@ -302,13 +304,7 @@ func NewFromVC(vc map[string]interface{}, headers jose.Headers,
 		return nil, err
 	}
 
-	var selectiveCredentialSubject map[string]interface{}
-
-	err = token.DecodeClaims(&selectiveCredentialSubject)
-	if err != nil {
-		return nil, err
-	}
-
+	selectiveCredentialSubject := utils.CopyMap(token.SignedJWT.Payload)
 	// move _sd_alg key from credential subject to vc as per example 4 in spec
 	vc[vcKey].(map[string]interface{})[common.SDAlgorithmKey] = selectiveCredentialSubject[common.SDAlgorithmKey]
 	delete(selectiveCredentialSubject, common.SDAlgorithmKey)
diff --git a/pkg/doc/sdjwt/verifier/verifier.go b/pkg/doc/sdjwt/verifier/verifier.go
index 7b83b4f8..80d532c7 100644
--- a/pkg/doc/sdjwt/verifier/verifier.go
+++ b/pkg/doc/sdjwt/verifier/verifier.go
@@ -16,7 +16,9 @@ import (
 	"time"
 
 	"github.com/go-jose/go-jose/v3/jwt"
+	"github.com/mitchellh/mapstructure"
 
+	"github.com/hyperledger/aries-framework-go/pkg/common/utils"
 	"github.com/hyperledger/aries-framework-go/pkg/doc/jose"
 	"github.com/hyperledger/aries-framework-go/pkg/doc/jose/jwk"
 	afgjwt "github.com/hyperledger/aries-framework-go/pkg/doc/jwt"
@@ -134,7 +136,7 @@ func Parse(combinedFormatForPresentation string, opts ...ParseOpt) (map[string]i
 	cfp := common.ParseCombinedFormatForPresentation(combinedFormatForPresentation)
 
 	// Validate the signature over the SD-JWT
-	signedJWT, err := afgjwt.Parse(cfp.SDJWT, jwtOpts...)
+	signedJWT, _, err := afgjwt.Parse(cfp.SDJWT, jwtOpts...)
 	if err != nil {
 		return nil, err
 	}
@@ -185,19 +187,12 @@ func verifyHolderBinding(sdJWT *afgjwt.JSONWebToken, holderBinding string, pOpts
 		return nil
 	}
 
-	var claims map[string]interface{}
-
-	err := sdJWT.DecodeClaims(&claims)
-	if err != nil {
-		return fmt.Errorf("failed to decode presentation claims: %w", err)
-	}
-
-	signatureVerifier, err := getSignatureVerifier(claims)
+	signatureVerifier, err := getSignatureVerifier(utils.CopyMap(sdJWT.Payload))
 	if err != nil {
 		return fmt.Errorf("failed to get signature verifier from presentation claims: %w", err)
 	}
 
-	holderJWT, err := afgjwt.Parse(holderBinding,
+	holderJWT, _, err := afgjwt.Parse(holderBinding,
 		afgjwt.WithSignatureVerifier(signatureVerifier))
 	if err != nil {
 		return fmt.Errorf("failed to parse holder binding: %w", err)
@@ -226,9 +221,19 @@ func verifyHolderJWT(holderJWT *afgjwt.JSONWebToken, pOpts *parseOpts) error {
 
 	var bindingPayload holderBindingPayload
 
-	err = holderJWT.DecodeClaims(&bindingPayload)
+	d, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
+		Result:           &bindingPayload,
+		TagName:          "json",
+		Squash:           true,
+		WeaklyTypedInput: true,
+		DecodeHook:       utils.JSONNumberToJwtNumericDate(),
+	})
 	if err != nil {
-		return fmt.Errorf("failed to decode holder claims: %w", err)
+		return fmt.Errorf("mapstruct verifyHodlder. error: %w", err)
+	}
+
+	if err = d.Decode(holderJWT.Payload); err != nil {
+		return fmt.Errorf("mapstruct verifyHodlder decode. error: %w", err)
 	}
 
 	if pOpts.expectedNonceForHolderBinding != "" && pOpts.expectedNonceForHolderBinding != bindingPayload.Nonce {
@@ -293,14 +298,7 @@ func getDisclosedClaims(disclosures []string, signedJWT *afgjwt.JSONWebToken) (m
 		return nil, fmt.Errorf("failed to get verified payload: %w", err)
 	}
 
-	var claims map[string]interface{}
-
-	err = signedJWT.DecodeClaims(&claims)
-	if err != nil {
-		return nil, fmt.Errorf("failed to decode verified payload: %w", err)
-	}
-
-	disclosedClaims, err := common.GetDisclosedClaims(disclosureClaims, claims)
+	disclosedClaims, err := common.GetDisclosedClaims(disclosureClaims, utils.CopyMap(signedJWT.Payload))
 	if err != nil {
 		return nil, fmt.Errorf("failed to get disclosed claims: %w", err)
 	}
@@ -359,9 +357,19 @@ func checkForDuplicates(values []string) error {
 func verifyJWT(signedJWT *afgjwt.JSONWebToken, leeway time.Duration) error {
 	var claims jwt.Claims
 
-	err := signedJWT.DecodeClaims(&claims)
+	d, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
+		Result:           &claims,
+		TagName:          "json",
+		Squash:           true,
+		WeaklyTypedInput: true,
+		DecodeHook:       utils.JSONNumberToJwtNumericDate(),
+	})
 	if err != nil {
-		return err
+		return fmt.Errorf("mapstruct verifyJWT. error: %w", err)
+	}
+
+	if err = d.Decode(signedJWT.Payload); err != nil {
+		return fmt.Errorf("mapstruct verifyJWT decode. error: %w", err)
 	}
 
 	// Validate checks claims in a token against expected values.
diff --git a/pkg/doc/signature/jsonld/processor.go b/pkg/doc/signature/jsonld/processor.go
index c0f0a22d..1a38b2a7 100644
--- a/pkg/doc/signature/jsonld/processor.go
+++ b/pkg/doc/signature/jsonld/processor.go
@@ -15,6 +15,7 @@ import (
 	"github.com/piprate/json-gold/ld"
 
 	"github.com/hyperledger/aries-framework-go/pkg/common/log"
+	"github.com/hyperledger/aries-framework-go/pkg/common/utils"
 )
 
 const (
@@ -246,7 +247,7 @@ func removeDuplicateIDs(inputDoc map[string]interface{}, proc *ld.JsonLdProcesso
 	var randomIds map[string]string
 
 	if len(duplicatedIDs) > 0 {
-		inputDocCopy = copyMap(inputDoc)
+		inputDocCopy = utils.CopyMap(inputDoc)
 
 		randomIds = make(map[string]string)
 
@@ -267,21 +268,6 @@ func removeDuplicateIDs(inputDoc map[string]interface{}, proc *ld.JsonLdProcesso
 	return inputDocCopy, randomIds, nil
 }
 
-func copyMap(m map[string]interface{}) map[string]interface{} {
-	cm := make(map[string]interface{})
-
-	for k, v := range m {
-		vm, ok := v.(map[string]interface{})
-		if ok {
-			cm[k] = copyMap(vm)
-		} else {
-			cm[k] = v
-		}
-	}
-
-	return cm
-}
-
 func getDuplicatedIDs(doc map[string]interface{}, proc *ld.JsonLdProcessor, options *ld.JsonLdOptions) (
 	map[string]bool, error) {
 	expand, err := proc.Expand(doc, options)
diff --git a/pkg/doc/util/didsignjwt/signjwt.go b/pkg/doc/util/didsignjwt/signjwt.go
index 15746614..f790c7ab 100644
--- a/pkg/doc/util/didsignjwt/signjwt.go
+++ b/pkg/doc/util/didsignjwt/signjwt.go
@@ -156,7 +156,7 @@ func SignJWT( // nolint: funlen,gocyclo
 //   - A VDR that can resolve the JWT's signing DID.
 func VerifyJWT(compactJWT string,
 	didResolver didResolver) error {
-	_, err := jwt.Parse(compactJWT, jwt.WithSignatureVerifier(jwt.NewVerifier(
+	_, _, err := jwt.Parse(compactJWT, jwt.WithSignatureVerifier(jwt.NewVerifier(
 		jwt.KeyResolverFunc(verifiable.NewVDRKeyResolver(didResolver).PublicKeyFetcher())),
 	))
 	if err != nil {
@@ -168,12 +168,12 @@ func VerifyJWT(compactJWT string,
 
 // ResolveSigningVM resolves a DID KeyID using the given did resolver, and returns either:
 //
-//  - the Verification Method identified by the given key ID, or
-//  - the first Assertion Method in the DID doc, if the DID provided has no fragment component.
+//   - the Verification Method identified by the given key ID, or
+//   - the first Assertion Method in the DID doc, if the DID provided has no fragment component.
 //
 // Returns:
-//  - a verification method suitable for signing.
-//  - the full DID#KID identifier of the returned verification method.
+//   - a verification method suitable for signing.
+//   - the full DID#KID identifier of the returned verification method.
 func ResolveSigningVM(kid string, didResolver didResolver) (*did.VerificationMethod, string, error) {
 	vmSplit := strings.Split(kid, "#")
 
diff --git a/pkg/doc/verifiable/jws.go b/pkg/doc/verifiable/jws.go
index 279a1d75..494dfa4c 100644
--- a/pkg/doc/verifiable/jws.go
+++ b/pkg/doc/verifiable/jws.go
@@ -6,6 +6,7 @@ SPDX-License-Identifier: Apache-2.0
 package verifiable
 
 import (
+	"encoding/json"
 	"fmt"
 
 	"github.com/hyperledger/aries-framework-go/pkg/doc/jose"
@@ -79,12 +80,12 @@ func unmarshalJWS(rawJwt string, checkProof bool, fetcher PublicKeyFetcher, clai
 		verifier = &noVerifier{}
 	}
 
-	jsonWebToken, err := jwt.Parse(rawJwt, jwt.WithSignatureVerifier(verifier))
+	_, claimsRaw, err := jwt.Parse(rawJwt, jwt.WithSignatureVerifier(verifier))
 	if err != nil {
 		return fmt.Errorf("parse JWT: %w", err)
 	}
 
-	err = jsonWebToken.DecodeClaims(claims)
+	err = json.Unmarshal(claimsRaw, claims)
 	if err != nil {
 		return err
 	}
diff --git a/pkg/doc/verifiable/jwt_unsecured.go b/pkg/doc/verifiable/jwt_unsecured.go
index a658a067..ab100a65 100644
--- a/pkg/doc/verifiable/jwt_unsecured.go
+++ b/pkg/doc/verifiable/jwt_unsecured.go
@@ -22,7 +22,7 @@ func marshalUnsecuredJWT(headers jose.Headers, claims interface{}) (string, erro
 }
 
 func unmarshalUnsecuredJWT(rawJWT string, claims interface{}) error {
-	token, err := jwt.Parse(rawJWT, jwt.WithSignatureVerifier(jwt.UnsecuredJWTVerifier()))
+	token, _, err := jwt.Parse(rawJWT, jwt.WithSignatureVerifier(jwt.UnsecuredJWTVerifier()))
 	if err != nil {
 		return fmt.Errorf("unmarshal unsecured JWT: %w", err)
 	}


Test patch:
diff --git a/pkg/doc/jwt/jwt_test.go b/pkg/doc/jwt/jwt_test.go
index aa30bfe8..964b073c 100644
--- a/pkg/doc/jwt/jwt_test.go
+++ b/pkg/doc/jwt/jwt_test.go
@@ -18,6 +18,7 @@ import (
 
 	"github.com/go-jose/go-jose/v3/json"
 	"github.com/go-jose/go-jose/v3/jwt"
+	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 
 	"github.com/hyperledger/aries-framework-go/pkg/doc/jose"
@@ -87,7 +88,7 @@ func TestNewUnsecured(t *testing.T) {
 		r.NoError(err)
 		r.NotEmpty(jwtUnsecured)
 
-		parsedJWT, err := Parse(jwtUnsecured, WithSignatureVerifier(UnsecuredJWTVerifier()))
+		parsedJWT, _, err := Parse(jwtUnsecured, WithSignatureVerifier(UnsecuredJWTVerifier()))
 		r.NoError(err)
 		r.NotNil(parsedJWT)
 
@@ -141,7 +142,7 @@ func TestParse(t *testing.T) {
 	verifier, err := NewEd25519Verifier(pubKey)
 	r.NoError(err)
 
-	jsonWebToken, err := Parse(jws, WithSignatureVerifier(verifier))
+	jsonWebToken, _, err := Parse(jws, WithSignatureVerifier(verifier))
 	r.NoError(err)
 
 	var parsedClaims map[string]interface{}
@@ -150,6 +151,11 @@ func TestParse(t *testing.T) {
 
 	r.Equal(claims, parsedClaims)
 
+	// parse without .Payload data
+	jsonWebToken, _, err = Parse(jws, WithSignatureVerifier(verifier), WithIgnoreClaimsMapDecoding(true))
+	r.NoError(err)
+	assert.Nil(t, jsonWebToken.Payload)
+
 	// parse detached JWT
 	jwsParts := strings.Split(jws, ".")
 	jwsDetached := fmt.Sprintf("%s..%s", jwsParts[0], jwsParts[2])
@@ -157,7 +163,7 @@ func TestParse(t *testing.T) {
 	jwsPayload, err := base64.RawURLEncoding.DecodeString(jwsParts[1])
 	require.NoError(t, err)
 
-	jsonWebToken, err = Parse(jwsDetached,
+	jsonWebToken, _, err = Parse(jwsDetached,
 		WithSignatureVerifier(verifier), WithJWTDetachedPayload(jwsPayload))
 	r.NoError(err)
 	r.NotNil(r, jsonWebToken)
@@ -165,7 +171,7 @@ func TestParse(t *testing.T) {
 	// claims is not JSON
 	jws, err = buildJWS(signer, "not JSON")
 	r.NoError(err)
-	token, err = Parse(jws, WithSignatureVerifier(verifier))
+	token, _, err = Parse(jws, WithSignatureVerifier(verifier))
 	r.Error(err)
 	r.Contains(err.Error(), "read JWT claims from JWS payload")
 	r.Nil(token)
@@ -174,7 +180,7 @@ func TestParse(t *testing.T) {
 	signer.headers = map[string]interface{}{"alg": "EdDSA", "typ": "JWM"}
 	jws, err = buildJWS(signer, map[string]interface{}{"iss": "Albert"})
 	r.NoError(err)
-	token, err = Parse(jws, WithSignatureVerifier(verifier))
+	token, _, err = Parse(jws, WithSignatureVerifier(verifier))
 	r.Error(err)
 	r.Contains(err.Error(), "typ is not JWT")
 	r.Nil(token)
@@ -183,19 +189,19 @@ func TestParse(t *testing.T) {
 	signer.headers = map[string]interface{}{"alg": "EdDSA", "typ": "JWT", "cty": "JWT"}
 	jws, err = buildJWS(signer, map[string]interface{}{"iss": "Albert"})
 	r.NoError(err)
-	token, err = Parse(jws, WithSignatureVerifier(verifier))
+	token, _, err = Parse(jws, WithSignatureVerifier(verifier))
 	r.Error(err)
 	r.Contains(err.Error(), "nested JWT is not supported")
 	r.Nil(token)
 
 	// handle compact JWS of invalid form
-	token, err = Parse("invalid.compact.JWS")
+	token, _, err = Parse("invalid.compact.JWS")
 	r.Error(err)
 	r.Contains(err.Error(), "parse JWT from compact JWS")
 	r.Nil(token)
 
 	// pass not compact JWS
-	token, err = Parse("invalid jws")
+	token, _, err = Parse("invalid jws")
 	r.Error(err)
 	r.EqualError(err, "JWT of compacted JWS form is supported only")
 	r.Nil(token)
diff --git a/pkg/doc/sdjwt/common/common_test.go b/pkg/doc/sdjwt/common/common_test.go
index d28c862c..7a3e9aed 100644
--- a/pkg/doc/sdjwt/common/common_test.go
+++ b/pkg/doc/sdjwt/common/common_test.go
@@ -18,6 +18,7 @@ import (
 
 	"github.com/stretchr/testify/require"
 
+	"github.com/hyperledger/aries-framework-go/pkg/common/utils"
 	"github.com/hyperledger/aries-framework-go/pkg/doc/jose"
 	afjwt "github.com/hyperledger/aries-framework-go/pkg/doc/jwt"
 )
@@ -142,7 +143,7 @@ func TestVerifyDisclosuresInSDJWT(t *testing.T) {
 		sdJWT := ParseCombinedFormatForIssuance(testCombinedFormatForIssuance)
 		require.Equal(t, 1, len(sdJWT.Disclosures))
 
-		signedJWT, err := afjwt.Parse(sdJWT.SDJWT, afjwt.WithSignatureVerifier(&NoopSignatureVerifier{}))
+		signedJWT, _, err := afjwt.Parse(sdJWT.SDJWT, afjwt.WithSignatureVerifier(&NoopSignatureVerifier{}))
 		require.NoError(t, err)
 
 		err = VerifyDisclosuresInSDJWT(sdJWT.Disclosures, signedJWT)
@@ -154,7 +155,7 @@ func TestVerifyDisclosuresInSDJWT(t *testing.T) {
 
 		sdJWT := ParseCombinedFormatForPresentation(specExample2bPresentation)
 
-		signedJWT, err := afjwt.Parse(sdJWT.SDJWT, afjwt.WithSignatureVerifier(&NoopSignatureVerifier{}))
+		signedJWT, _, err := afjwt.Parse(sdJWT.SDJWT, afjwt.WithSignatureVerifier(&NoopSignatureVerifier{}))
 		require.NoError(t, err)
 
 		err = VerifyDisclosuresInSDJWT(sdJWT.Disclosures, signedJWT)
@@ -190,7 +191,7 @@ func TestVerifyDisclosuresInSDJWT(t *testing.T) {
 		sdJWT := ParseCombinedFormatForIssuance(testCombinedFormatForIssuance)
 		require.Equal(t, 1, len(sdJWT.Disclosures))
 
-		signedJWT, err := afjwt.Parse(sdJWT.SDJWT, afjwt.WithSignatureVerifier(&NoopSignatureVerifier{}))
+		signedJWT, _, err := afjwt.Parse(sdJWT.SDJWT, afjwt.WithSignatureVerifier(&NoopSignatureVerifier{}))
 		require.NoError(t, err)
 
 		err = VerifyDisclosuresInSDJWT(append(sdJWT.Disclosures, additionalDisclosure), signedJWT)
@@ -269,7 +270,7 @@ func TestVerifyDisclosuresInSDJWT(t *testing.T) {
 	t.Run("error - selective disclosures must be a string", func(t *testing.T) {
 		payload := make(map[string]interface{})
 		payload[SDAlgorithmKey] = testAlg
-		payload[SDKey] = []int{123}
+		payload[SDKey] = []float64{123}
 
 		signedJWT, err := afjwt.NewSigned(payload, nil, signer)
 		r.NoError(err)
@@ -344,7 +345,7 @@ func TestGetDisclosedClaims(t *testing.T) {
 	disclosureClaims, err := GetDisclosureClaims(cfi.Disclosures)
 	r.NoError(err)
 
-	token, err := afjwt.Parse(cfi.SDJWT, afjwt.WithSignatureVerifier(&NoopSignatureVerifier{}))
+	token, _, err := afjwt.Parse(cfi.SDJWT, afjwt.WithSignatureVerifier(&NoopSignatureVerifier{}))
 	r.NoError(err)
 
 	var claims map[string]interface{}
@@ -365,7 +366,7 @@ func TestGetDisclosedClaims(t *testing.T) {
 	})
 
 	t.Run("success - with complex object", func(t *testing.T) {
-		testClaims := copyMap(claims)
+		testClaims := utils.CopyMap(claims)
 
 		additionalDigest, err := GetHash(crypto.SHA256, additionalDisclosure)
 		r.NoError(err)
@@ -395,7 +396,7 @@ func TestGetDisclosedClaims(t *testing.T) {
 	})
 
 	t.Run("error - claim value contains _sd", func(t *testing.T) {
-		testClaims := copyMap(claims)
+		testClaims := utils.CopyMap(claims)
 
 		additionalDigest, err := GetHash(crypto.SHA256, additionalDisclosure)
 		r.NoError(err)
@@ -421,7 +422,7 @@ func TestGetDisclosedClaims(t *testing.T) {
 	})
 
 	t.Run("error - same claim key at the same level ", func(t *testing.T) {
-		testClaims := copyMap(claims)
+		testClaims := utils.CopyMap(claims)
 
 		parentObj := make(map[string]interface{})
 		parentObj["given_name"] = "Albert"
@@ -439,7 +440,7 @@ func TestGetDisclosedClaims(t *testing.T) {
 	})
 
 	t.Run("error - digest included in more than one spot ", func(t *testing.T) {
-		testClaims := copyMap(claims)
+		testClaims := utils.CopyMap(claims)
 
 		parentObj := make(map[string]interface{})
 		parentObj["last_name"] = "Smith"
@@ -457,7 +458,7 @@ func TestGetDisclosedClaims(t *testing.T) {
 	})
 
 	t.Run("error - with complex object", func(t *testing.T) {
-		testClaims := copyMap(claims)
+		testClaims := utils.CopyMap(claims)
 
 		parentObj := make(map[string]interface{})
 		parentObj["given_name"] = "Albert"
diff --git a/pkg/doc/sdjwt/issuer/issuer_test.go b/pkg/doc/sdjwt/issuer/issuer_test.go
index 9644d50d..252964f9 100644
--- a/pkg/doc/sdjwt/issuer/issuer_test.go
+++ b/pkg/doc/sdjwt/issuer/issuer_test.go
@@ -367,7 +367,7 @@ func TestNew(t *testing.T) {
 		cfi := common.ParseCombinedFormatForIssuance(combinedFormatForIssuance)
 		r.Equal(1, len(cfi.Disclosures))
 
-		afjwtToken, err := afjwt.Parse(cfi.SDJWT, afjwt.WithSignatureVerifier(verifier))
+		afjwtToken, _, err := afjwt.Parse(cfi.SDJWT, afjwt.WithSignatureVerifier(verifier))
 		r.NoError(err)
 
 		var parsedClaims map[string]interface{}
@@ -877,7 +877,7 @@ func verifyEd25519(jws string, pubKey ed25519.PublicKey) error {
 		Verifier: v,
 	})
 
-	token, err := afjwt.Parse(jws, afjwt.WithSignatureVerifier(sVerifier))
+	token, _, err := afjwt.Parse(jws, afjwt.WithSignatureVerifier(sVerifier))
 	if err != nil {
 		return err
 	}
@@ -897,7 +897,7 @@ func verifyRS256(jws string, pubKey *rsa.PublicKey) error {
 		Verifier: v,
 	})
 
-	token, err := afjwt.Parse(jws, afjwt.WithSignatureVerifier(sVerifier))
+	token, _, err := afjwt.Parse(jws, afjwt.WithSignatureVerifier(sVerifier))
 	if err != nil {
 		return err
 	}
diff --git a/pkg/doc/sdjwt/verifier/verifier_test.go b/pkg/doc/sdjwt/verifier/verifier_test.go
index dbc7873c..beb3eecb 100644
--- a/pkg/doc/sdjwt/verifier/verifier_test.go
+++ b/pkg/doc/sdjwt/verifier/verifier_test.go
@@ -76,7 +76,7 @@ func TestParse(t *testing.T) {
 	})
 
 	t.Run("success - VC sample", func(t *testing.T) {
-		token, err := afjwt.Parse(vcSDJWT, afjwt.WithSignatureVerifier(&holder.NoopSignatureVerifier{}))
+		token, _, err := afjwt.Parse(vcSDJWT, afjwt.WithSignatureVerifier(&holder.NoopSignatureVerifier{}))
 		r.NoError(err)
 
 		var payload map[string]interface{}
diff --git a/test/bdd/pkg/verifiable/verifiable_steps.go b/test/bdd/pkg/verifiable/verifiable_steps.go
index 0153e2b7..f44f8789 100644
--- a/test/bdd/pkg/verifiable/verifiable_steps.go
+++ b/test/bdd/pkg/verifiable/verifiable_steps.go
@@ -46,80 +46,96 @@ import (
 	bddldcontext "github.com/hyperledger/aries-framework-go/test/bdd/pkg/ldcontext"
 )
 
+// picked up from https://github.com/decentralized-identity/JWS-Test-Suite/blob/main/data/implementations/spruce/credential-0--key-0-ed25519.vc-jwt.json
+//
 //go:embed testdata/interop_credential_1_ed25519.jwt
 //nolint:lll
-// picked up from https://github.com/decentralized-identity/JWS-Test-Suite/blob/main/data/implementations/spruce/credential-0--key-0-ed25519.vc-jwt.json
 var credential1Ed25519 string //nolint:gochecknoglobals
 
+// picked up from https://github.com/decentralized-identity/JWS-Test-Suite/blob/main/data/implementations/spruce/credential-1--key-0-ed25519.vc-jwt.json
+//
 //go:embed testdata/interop_credential_2_ed25519.jwt
 //nolint:lll
-// picked up from https://github.com/decentralized-identity/JWS-Test-Suite/blob/main/data/implementations/spruce/credential-1--key-0-ed25519.vc-jwt.json
 var credential2Ed25519 string //nolint:gochecknoglobals
 
+// picked up from https://github.com/decentralized-identity/JWS-Test-Suite/blob/main/data/implementations/spruce/credential-2--key-0-ed25519.vc-jwt.json
+//
 //go:embed testdata/interop_credential_3_ed25519.jwt
 //nolint:lll
-// picked up from https://github.com/decentralized-identity/JWS-Test-Suite/blob/main/data/implementations/spruce/credential-2--key-0-ed25519.vc-jwt.json
 var credential3Ed25519 string //nolint:gochecknoglobals
 
+// picked up from https://github.com/decentralized-identity/JWS-Test-Suite/blob/main/data/implementations/transmute/credential-0--key-1-secp256k1.vc-jwt.json
+//
 //go:embed testdata/interop_credential_4_secp256k1.jwt
 //nolint:lll
-// picked up from https://github.com/decentralized-identity/JWS-Test-Suite/blob/main/data/implementations/transmute/credential-0--key-1-secp256k1.vc-jwt.json
 var credential4Secp256k1 string //nolint:gochecknoglobals
 
+// picked up from https://github.com/decentralized-identity/JWS-Test-Suite/blob/main/data/implementations/transmute/credential-1--key-1-secp256k1.vc-jwt.json
+//
 //go:embed testdata/interop_credential_5_secp256k1.jwt
 //nolint:lll
-// picked up from https://github.com/decentralized-identity/JWS-Test-Suite/blob/main/data/implementations/transmute/credential-1--key-1-secp256k1.vc-jwt.json
 var credential5Secp256k1 string //nolint:gochecknoglobals
 
+// picked up from https://github.com/decentralized-identity/JWS-Test-Suite/blob/main/data/implementations/transmute/credential-2--key-1-secp256k1.vc-jwt.json
+//
 //go:embed testdata/interop_credential_6_secp256k1.jwt
 //nolint:lll
-// picked up from https://github.com/decentralized-identity/JWS-Test-Suite/blob/main/data/implementations/transmute/credential-2--key-1-secp256k1.vc-jwt.json
 var credential6Secp256k1 string //nolint:gochecknoglobals
 
+// picked up from https://github.com/decentralized-identity/JWS-Test-Suite/blob/main/data/implementations/transmute/credential-0--key-2-secp256r1.vc-jwt.json
+//
 //go:embed testdata/interop_credential_7_secp256r1.jwt
 //nolint:lll
-// picked up from https://github.com/decentralized-identity/JWS-Test-Suite/blob/main/data/implementations/transmute/credential-0--key-2-secp256r1.vc-jwt.json
 var credential7Secp256r1 string //nolint:gochecknoglobals
 
+// picked up from https://github.com/decentralized-identity/JWS-Test-Suite/blob/main/data/implementations/transmute/credential-1--key-2-secp256r1.vc-jwt.json
+//
 //go:embed testdata/interop_credential_8_secp256r1.jwt
 //nolint:lll
-// picked up from https://github.com/decentralized-identity/JWS-Test-Suite/blob/main/data/implementations/transmute/credential-1--key-2-secp256r1.vc-jwt.json
 var credential8Secp256r1 string //nolint:gochecknoglobals
 
+// picked up from https://github.com/decentralized-identity/JWS-Test-Suite/blob/main/data/implementations/transmute/credential-2--key-2-secp256r1.vc-jwt.json
+//
 //go:embed testdata/interop_credential_9_secp256r1.jwt
 //nolint:lll
-// picked up from https://github.com/decentralized-identity/JWS-Test-Suite/blob/main/data/implementations/transmute/credential-2--key-2-secp256r1.vc-jwt.json
 var credential9Secp256r1 string //nolint:gochecknoglobals
 
+// picked up from https://github.com/decentralized-identity/JWS-Test-Suite/blob/main/data/implementations/transmute/credential-0--key-3-secp384r1.vc-jwt.json
+//
 //go:embed testdata/interop_credential_10_secp384r1.jwt
 //nolint:lll
-// picked up from https://github.com/decentralized-identity/JWS-Test-Suite/blob/main/data/implementations/transmute/credential-0--key-3-secp384r1.vc-jwt.json
 var credential10Secp384r1 string //nolint:gochecknoglobals
 
+// picked up from https://github.com/decentralized-identity/JWS-Test-Suite/blob/main/data/implementations/transmute/credential-1--key-3-secp384r1.vc-jwt.json
+//
 //go:embed testdata/interop_credential_11_secp384r1.jwt
 //nolint:lll
-// picked up from https://github.com/decentralized-identity/JWS-Test-Suite/blob/main/data/implementations/transmute/credential-1--key-3-secp384r1.vc-jwt.json
 var credential11Secp384r1 string //nolint:gochecknoglobals
 
+// picked up from https://github.com/decentralized-identity/JWS-Test-Suite/blob/main/data/implementations/transmute/credential-2--key-3-secp384r1.vc-jwt.json
+//
 //go:embed testdata/interop_credential_12_secp384r1.jwt
 //nolint:lll
-// picked up from https://github.com/decentralized-identity/JWS-Test-Suite/blob/main/data/implementations/transmute/credential-2--key-3-secp384r1.vc-jwt.json
 var credential12Secp384r1 string //nolint:gochecknoglobals
 
-//go:embed testdata/interop_key_ed25519.jwk
 // ref https://github.com/decentralized-identity/JWS-Test-Suite/blob/main/data/keys/key-0-ed25519.json
+//
+//go:embed testdata/interop_key_ed25519.jwk
 var interopKeyEd25519 string //nolint:gochecknoglobals
 
-//go:embed testdata/interop_key_secp256k1.jwk
 // ref https://github.com/decentralized-identity/JWS-Test-Suite/blob/main/data/keys/key-1-secp256k1.json
+//
+//go:embed testdata/interop_key_secp256k1.jwk
 var interopKeyECDSASecp256k1 string //nolint:gochecknoglobals
 
-//go:embed testdata/interop_key_secp256r1.jwk
 // ref https://github.com/decentralized-identity/JWS-Test-Suite/blob/main/data/keys/key-2-secp256r1.json
+//
+//go:embed testdata/interop_key_secp256r1.jwk
 var interopKeyECDSASecp256r1 string //nolint:gochecknoglobals
 
-//go:embed testdata/interop_key_secp384r1.jwk
 // ref https://github.com/decentralized-identity/JWS-Test-Suite/blob/main/data/keys/key-3-secp384r1.json
+//
+//go:embed testdata/interop_key_secp384r1.jwk
 var interopKeyECDSASecp384r1 string //nolint:gochecknoglobals
 
 // SDKSteps is steps for verifiable credentials using client SDK.
@@ -290,7 +306,7 @@ func (s *SDKSteps) loadInteropCredentialAndVerify(claimID, signature string) err
 		return err
 	}
 
-	jwtCred, err := jwt.Parse(interopCred.JWT, jwt.WithSignatureVerifier(s.joseVerifier[signature]))
+	jwtCred, _, err := jwt.Parse(interopCred.JWT, jwt.WithSignatureVerifier(s.joseVerifier[signature]))
 	if jwtCred == nil {
 		return fmt.Errorf("interop jwt cred was nil, err: %w", err)
 	}