Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions auth/api/auth/v1/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@ func (m *mockAuthClient) AuthorizationEndpointEnabled() bool {
return true
}

func (m *mockAuthClient) OpenID4VCIEnabled() bool {
return true
}

func (m *mockAuthClient) AuthzServer() oauth.AuthorizationServer {
return m.authzServer
}
Expand Down
19 changes: 18 additions & 1 deletion auth/api/iam/openid4vp.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ import (
"encoding/json"
"errors"
"fmt"

"github.com/nuts-foundation/nuts-node/http/user"
"github.com/nuts-foundation/nuts-node/vcr/types"

"net/http"
"net/url"
"slices"
Expand Down Expand Up @@ -536,7 +539,7 @@ func (r Wrapper) handleAuthorizeResponseSubmission(ctx context.Context, request
if err != nil {
return nil, oauth.OAuth2Error{
Code: oauth.InvalidRequest,
Description: "presentation(s) or contained credential(s) are invalid",
Description: verificationErrorDescription(err),
InternalError: err,
RedirectURI: callbackURI,
}
Expand Down Expand Up @@ -764,3 +767,17 @@ func oauthError(code oauth.ErrorCode, description string, internalError ...error
InternalError: errors.Join(internalError...),
}
}

// verificationErrorDescription returns a more specific error description when DID resolution fails,
// otherwise returns the generic error message. This improves user experience by providing actionable
// error information for common DID resolution issues while maintaining security for other errors.
func verificationErrorDescription(err error) string {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of making a new error message, just use

"presentation(s) or contained credential(s) are invalid: " + err.Error()

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated in a9b37f2 to use err.Error() directly

// Check for DID resolution errors
if errors.Is(err, resolver.ErrNotFound) || errors.Is(err, resolver.ErrKeyNotFound) || strings.Contains(err.Error(), "unable to resolve") ||
errors.Is(err, types.ErrStatusNotFound) || errors.Is(err, types.ErrRevoked) || errors.Is(err, types.ErrCredentialNotValidAtTime) || errors.Is(err, types.ErrPresentationNotValidAtTime) {
return "presentation(s) or credential(s) verification failed: " + err.Error()
}

// Default generic message for other errors
return "presentation(s) or credential(s) verification failed"
}
29 changes: 29 additions & 0 deletions auth/api/iam/openid4vp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ package iam
import (
"context"
"encoding/json"
"errors"
"fmt"
"github.com/nuts-foundation/nuts-node/http/user"
"net/http"
"net/url"
Expand All @@ -35,6 +37,7 @@ import (
"github.com/nuts-foundation/nuts-node/storage"
"github.com/nuts-foundation/nuts-node/test"
"github.com/nuts-foundation/nuts-node/vcr/pe"
"github.com/nuts-foundation/nuts-node/vdr/resolver"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
Expand Down Expand Up @@ -964,5 +967,31 @@ func putNonce(ctx *testCtx, nonce string) {

func putCodeSession(ctx *testCtx, code string, oauthSession OAuthSession) {
_ = ctx.client.oauthCodeStore().Put(code, oauthSession)
}

func Test_verificationErrorDescription(t *testing.T) {
t.Run("DID not found error", func(t *testing.T) {
err := resolver.ErrNotFound
result := verificationErrorDescription(err)
assert.Equal(t, "presentation(s) or contained credential(s) are invalid: unable to find the DID document", result)
})

t.Run("Key not found error", func(t *testing.T) {
err := resolver.ErrKeyNotFound
result := verificationErrorDescription(err)
assert.Equal(t, "presentation(s) or contained credential(s) are invalid: key not found in DID document", result)
})

t.Run("Wrapped DID resolution error", func(t *testing.T) {
err := fmt.Errorf("unable to resolve valid signing key: %w", resolver.ErrNotFound)
result := verificationErrorDescription(err)
assert.Equal(t, "presentation(s) or contained credential(s) are invalid: unable to resolve valid signing key: unable to find the DID document", result)
})

t.Run("Generic error returns default message", func(t *testing.T) {
err := errors.New("some other error")
result := verificationErrorDescription(err)
assert.Equal(t, "presentation(s) or contained credential(s) are invalid", result)
})
}

2 changes: 1 addition & 1 deletion auth/api/iam/s2s_vptoken.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ func (r Wrapper) handleS2SAccessTokenRequest(ctx context.Context, clientID strin
if err != nil {
return nil, oauth.OAuth2Error{
Code: oauth.InvalidRequest,
Description: "presentation(s) or contained credential(s) are invalid",
Description: verificationErrorDescription(err),
InternalError: err,
}
}
Expand Down
4 changes: 1 addition & 3 deletions vcr/pe/schema/gen/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,4 @@ module github.com/nuts-foundation/nuts-node/vcr/pe/gen/schema

go 1.21

require (
github.com/a-h/generate v0.0.0-20220105161013-96c14dfdfb60 // indirect
)
require github.com/a-h/generate v0.0.0-20220105161013-96c14dfdfb60
14 changes: 0 additions & 14 deletions vcr/pe/schema/gen/go.sum
Original file line number Diff line number Diff line change
@@ -1,16 +1,2 @@
github.com/PaesslerAG/gval v1.0.0 h1:GEKnRwkWDdf9dOmKcNrar9EA1bz1z9DqPIO1+iLzhd8=
github.com/PaesslerAG/gval v1.0.0/go.mod h1:y/nm5yEyTeX6av0OfKJNp9rBNj2XrGhAf5+v24IBN1I=
github.com/PaesslerAG/gval v1.2.2 h1:Y7iBzhgE09IGTt5QgGQ2IdaYYYOU134YGHBThD+wm9E=
github.com/PaesslerAG/gval v1.2.2/go.mod h1:XRFLwvmkTEdYziLdaCeCa5ImcGVrfQbeNUbVR+C6xac=
github.com/PaesslerAG/jsonpath v0.1.0/go.mod h1:4BzmtoM/PI8fPO4aQGIusjGxGir2BzcV0grWtFzq1Y8=
github.com/PaesslerAG/jsonpath v0.1.1 h1:c1/AToHQMVsduPAa4Vh6xp2U0evy4t8SWp8imEsylIk=
github.com/PaesslerAG/jsonpath v0.1.1/go.mod h1:lVboNxFGal/VwW6d9JzIy56bUsYAP6tH/x80vjnCseY=
github.com/PaesslerAG/jsonpath v0.1.2-0.20230323094847-3484786d6f97 h1:XIsQOSBJi/9Bexr+rjUpuYi0IkQ+YqNKKlE7Yt/sw9Q=
github.com/PaesslerAG/jsonpath v0.1.2-0.20230323094847-3484786d6f97/go.mod h1:zTyVtYhYjcHpfCtqnCMxejgp0pEEwb/xJzhn05NrkJk=
github.com/a-h/generate v0.0.0-20220105161013-96c14dfdfb60 h1:/rNdG6EuzjwcR1KRFpF+9qWmWh2xIcz84QOeMGr/2L8=
github.com/a-h/generate v0.0.0-20220105161013-96c14dfdfb60/go.mod h1:traiLYQ0YD7qUMCdjo6/jSaJRPHXniX4HVs+PhEhYpc=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
Loading