Skip to content

Commit b6f3b1e

Browse files
muhlemmerlivio-a
andauthoredAug 9, 2024··
feat(op): allow returning of parent errors to client (#629)
* feat(op): allow returning of parent errors to client * update godoc --------- Co-authored-by: Livio Spring <livio.a@gmail.com>
1 parent 6f0a630 commit b6f3b1e

File tree

2 files changed

+70
-0
lines changed

2 files changed

+70
-0
lines changed
 

‎pkg/oidc/error.go

+31
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package oidc
22

33
import (
4+
"encoding/json"
45
"errors"
56
"fmt"
67
"log/slog"
@@ -133,6 +134,24 @@ type Error struct {
133134
Description string `json:"error_description,omitempty" schema:"error_description,omitempty"`
134135
State string `json:"state,omitempty" schema:"state,omitempty"`
135136
redirectDisabled bool `schema:"-"`
137+
returnParent bool `schema:"-"`
138+
}
139+
140+
func (e *Error) MarshalJSON() ([]byte, error) {
141+
m := struct {
142+
Error errorType `json:"error"`
143+
ErrorDescription string `json:"error_description,omitempty"`
144+
State string `json:"state,omitempty"`
145+
Parent string `json:"parent,omitempty"`
146+
}{
147+
Error: e.ErrorType,
148+
ErrorDescription: e.Description,
149+
State: e.State,
150+
}
151+
if e.returnParent {
152+
m.Parent = e.Parent.Error()
153+
}
154+
return json.Marshal(m)
136155
}
137156

138157
func (e *Error) Error() string {
@@ -165,6 +184,18 @@ func (e *Error) WithParent(err error) *Error {
165184
return e
166185
}
167186

187+
// WithReturnParentToClient allows returning the set parent error to the HTTP client.
188+
// Currently it only supports setting the parent inside JSON responses, not redirect URLs.
189+
// As Go errors don't unmarshal well, only the marshaller is implemented for the moment.
190+
//
191+
// Warning: parent errors may contain sensitive data or unwanted details about the server status.
192+
// Also, the `parent` field is not a standard error field and might confuse certain clients
193+
// that require fully compliant responses.
194+
func (e *Error) WithReturnParentToClient(b bool) *Error {
195+
e.returnParent = b
196+
return e
197+
}
198+
168199
func (e *Error) WithDescription(desc string, args ...any) *Error {
169200
e.Description = fmt.Sprintf(desc, args...)
170201
return e

‎pkg/oidc/error_test.go

+39
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
package oidc
22

33
import (
4+
"encoding/json"
5+
"errors"
46
"io"
57
"log/slog"
68
"testing"
79

810
"github.com/stretchr/testify/assert"
11+
"github.com/stretchr/testify/require"
912
)
1013

1114
func TestDefaultToServerError(t *testing.T) {
@@ -151,3 +154,39 @@ func TestError_LogValue(t *testing.T) {
151154
})
152155
}
153156
}
157+
158+
func TestError_MarshalJSON(t *testing.T) {
159+
tests := []struct {
160+
name string
161+
e *Error
162+
want string
163+
}{
164+
{
165+
name: "simple error",
166+
e: ErrAccessDenied(),
167+
want: `{"error":"access_denied","error_description":"The authorization request was denied."}`,
168+
},
169+
{
170+
name: "with description",
171+
e: ErrAccessDenied().WithDescription("oops"),
172+
want: `{"error":"access_denied","error_description":"oops"}`,
173+
},
174+
{
175+
name: "with parent",
176+
e: ErrServerError().WithParent(errors.New("oops")),
177+
want: `{"error":"server_error"}`,
178+
},
179+
{
180+
name: "with return parent",
181+
e: ErrServerError().WithParent(errors.New("oops")).WithReturnParentToClient(true),
182+
want: `{"error":"server_error","parent":"oops"}`,
183+
},
184+
}
185+
for _, tt := range tests {
186+
t.Run(tt.name, func(t *testing.T) {
187+
got, err := json.Marshal(tt.e)
188+
require.NoError(t, err)
189+
assert.JSONEq(t, tt.want, string(got))
190+
})
191+
}
192+
}

0 commit comments

Comments
 (0)
Please sign in to comment.