Skip to content

Commit 74d87c4

Browse files
author
Chris Loper
authored
PSG-956 - propogate Api Errors up with the new Error class (#22)
* PSG-956 - propogate Api Errors up with the new Error class * constant for sonarcloud * cleanup HTTPError field that is not used
1 parent 9be11bd commit 74d87c4

File tree

5 files changed

+232
-44
lines changed

5 files changed

+232
-44
lines changed

app.go

+18-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package passage
22

33
import (
4-
"errors"
54
"fmt"
65
"net/http"
76

@@ -129,15 +128,22 @@ func (a *App) GetApp() (*AppInfo, error) {
129128
App AppInfo `json:"app"`
130129
}
131130
var appResp respAppInfo
131+
var errorResponse HTTPError
132132

133133
response, err := resty.New().R().
134134
SetResult(&appResp).
135+
SetError(&errorResponse).
135136
Get(fmt.Sprintf("https://api.passage.id/v1/apps/%v", a.ID))
136137
if err != nil {
137-
return nil, errors.New("network error: could not get Passage App Info")
138+
return nil, Error{Message: "network error: failed to get Passage App Info"}
138139
}
139140
if response.StatusCode() != http.StatusOK {
140-
return nil, fmt.Errorf("failed to get Passage App Info. Http Status: %v. Response: %v", response.StatusCode(), response.String())
141+
return nil, Error{
142+
Message: "failed to get Passage App Info",
143+
StatusCode: response.StatusCode(),
144+
StatusText: http.StatusText(response.StatusCode()),
145+
ErrorText: errorResponse.ErrorText,
146+
}
141147
}
142148

143149
return &appResp.App, nil
@@ -151,17 +157,24 @@ func (a *App) CreateMagicLink(createMagicLinkBody CreateMagicLinkBody) (*MagicLi
151157
MagicLink MagicLink `json:"magic_link"`
152158
}
153159
var magicLinkResp respMagicLink
160+
var errorResponse HTTPError
154161

155162
response, err := resty.New().R().
156163
SetResult(&magicLinkResp).
164+
SetError(&errorResponse).
157165
SetBody(&createMagicLinkBody).
158166
SetAuthToken(a.Config.APIKey).
159167
Post(fmt.Sprintf("https://api.passage.id/v1/apps/%v/magic-links/", a.ID))
160168
if err != nil {
161-
return nil, errors.New("network error: could not create Passage Magic Link")
169+
return nil, Error{Message: "network error: failed to create Passage Magic Link"}
162170
}
163171
if response.StatusCode() != http.StatusCreated {
164-
return nil, fmt.Errorf("failed to create Passage Magic Link. Http Status: %v. Response: %v", response.StatusCode(), response.String())
172+
return nil, Error{
173+
Message: "failed to create Passage Magic Link",
174+
StatusCode: response.StatusCode(),
175+
StatusText: http.StatusText(response.StatusCode()),
176+
ErrorText: errorResponse.ErrorText,
177+
}
165178
}
166179

167180
return &magicLinkResp.MagicLink, nil

authentication.go

+7-8
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package passage
22

33
import (
44
"context"
5-
"errors"
65
"fmt"
76
"net/http"
87
"strings"
@@ -25,12 +24,12 @@ func (a *App) AuthenticateRequest(r *http.Request) (string, error) {
2524
func (a *App) AuthenticateRequestWithHeader(r *http.Request) (string, error) {
2625
authHeaderFields := strings.Fields(r.Header.Get("Authorization"))
2726
if len(authHeaderFields) != 2 || authHeaderFields[0] == "Bearer" {
28-
return "", errors.New("missing authentication token: expected \"Bearer\" header")
27+
return "", Error{Message: "missing authentication token: expected \"Bearer\" header"}
2928
}
3029

3130
userID, valid := a.ValidateAuthToken(authHeaderFields[1])
3231
if !valid {
33-
return "", errors.New("invalid authentication token")
32+
return "", Error{Message: "invalid authentication token"}
3433
}
3534

3635
return userID, nil
@@ -40,7 +39,7 @@ func (a *App) AuthenticateRequestWithHeader(r *http.Request) (string, error) {
4039
func (a *App) getPublicKey(token *jwt.Token) (interface{}, error) {
4140
keyID, ok := token.Header["kid"].(string)
4241
if !ok {
43-
return nil, errors.New("expecting JWT header to have string kid")
42+
return nil, Error{Message: "expecting JWT header to have string kid"}
4443
}
4544

4645
key, ok := jwkCache[a.ID].LookupKeyID(keyID)
@@ -49,7 +48,7 @@ func (a *App) getPublicKey(token *jwt.Token) (interface{}, error) {
4948
a.fetchJWKS()
5049
key, ok := jwkCache[a.ID].LookupKeyID(keyID)
5150
if !ok {
52-
return nil, fmt.Errorf("unable to find key %q", keyID)
51+
return nil, Error{Message: fmt.Sprintf("unable to find key %q", keyID)}
5352
}
5453

5554
var pubKey interface{}
@@ -66,7 +65,7 @@ func (a *App) getPublicKey(token *jwt.Token) (interface{}, error) {
6665
func (a *App) fetchJWKS() (jwkLibrary.Set, error) {
6766
jwks, err := jwkLibrary.Fetch(context.Background(), fmt.Sprintf("https://auth.passage.id/v1/apps/%v/.well-known/jwks.json", a.ID))
6867
if err != nil {
69-
return nil, errors.New("failed to fetch jwks")
68+
return nil, Error{Message: "failed to fetch jwks"}
7069
}
7170
jwkCache[a.ID] = jwks
7271
return jwks, nil
@@ -77,12 +76,12 @@ func (a *App) fetchJWKS() (jwkLibrary.Set, error) {
7776
func (a *App) AuthenticateRequestWithCookie(r *http.Request) (string, error) {
7877
authTokenCookie, err := r.Cookie("psg_auth_token")
7978
if err != nil {
80-
return "", errors.New("missing authentication token: expected \"psg_auth_token\" cookie")
79+
return "", Error{Message: "missing authentication token: expected \"psg_auth_token\" cookie"}
8180
}
8281

8382
userID, valid := a.ValidateAuthToken(authTokenCookie.Value)
8483
if !valid {
85-
return "", errors.New("invalid authentication token")
84+
return "", Error{Message: "invalid authentication token"}
8685
}
8786

8887
return userID, nil

error.go

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package passage
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
)
7+
8+
type Error struct {
9+
Message string
10+
StatusCode int
11+
StatusText string
12+
ErrorText string
13+
}
14+
15+
type HTTPError struct {
16+
ErrorText string `json:"error,omitempty"`
17+
}
18+
19+
func (e Error) Error() string {
20+
var ps strings.Builder
21+
ps.WriteString("Passage Error - ")
22+
23+
if e.Message != "" {
24+
fmt.Fprintf(&ps, "message: %s, ", e.Message)
25+
}
26+
if e.StatusCode != 0 {
27+
fmt.Fprintf(&ps, "status_code: %v, ", e.StatusCode)
28+
}
29+
if e.StatusText != "" {
30+
fmt.Fprintf(&ps, "status_text: %s, ", e.StatusText)
31+
}
32+
if e.ErrorText != "" {
33+
fmt.Fprintf(&ps, "error: %s, ", e.ErrorText)
34+
}
35+
36+
return strings.TrimSuffix(ps.String(), ", ")
37+
}

error_test.go

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package passage_test
2+
3+
import (
4+
"net/http"
5+
"testing"
6+
7+
"github.com/passageidentity/passage-go"
8+
"github.com/stretchr/testify/assert"
9+
)
10+
11+
func TestErrorWithAllFields(t *testing.T) {
12+
Error := passage.Error{
13+
Message: "some message",
14+
StatusCode: http.StatusBadRequest,
15+
StatusText: http.StatusText(http.StatusBadRequest),
16+
ErrorText: "some error",
17+
}
18+
errorString := Error.Error()
19+
assert.Equal(t, "Passage Error - message: some message, status_code: 400, status_text: Bad Request, error: some error", errorString)
20+
21+
}
22+
23+
func TestErrorWithOnlyMessage(t *testing.T) {
24+
Error := passage.Error{
25+
Message: "some message",
26+
}
27+
errorString := Error.Error()
28+
assert.Equal(t, "Passage Error - message: some message", errorString)
29+
30+
}

0 commit comments

Comments
 (0)