1
21
22 package fosite
23
24 import (
25 "encoding/json"
26 "fmt"
27 "net/http"
28 "net/url"
29 "strings"
30
31 "github.com/ory/fosite/i18n"
32 "github.com/ory/x/errorsx"
33 "golang.org/x/text/language"
34
35 stderr "errors"
36
37 "github.com/pkg/errors"
38 )
39
40 var (
41
42
43 ErrInvalidatedAuthorizeCode = errors.New("Authorization code has ben invalidated")
44
45
46 ErrSerializationFailure = errors.New("The request could not be completed due to concurrent access")
47 ErrUnknownRequest = &RFC6749Error{
48 ErrorField: errUnknownErrorName,
49 DescriptionField: "The handler is not responsible for this request.",
50 CodeField: http.StatusBadRequest,
51 }
52 ErrRequestForbidden = &RFC6749Error{
53 ErrorField: errRequestForbidden,
54 DescriptionField: "The request is not allowed.",
55 HintField: "You are not allowed to perform this action.",
56 CodeField: http.StatusForbidden,
57 }
58 ErrInvalidRequest = &RFC6749Error{
59 ErrorField: errInvalidRequestName,
60 DescriptionField: "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed.",
61 HintField: "Make sure that the various parameters are correct, be aware of case sensitivity and trim your parameters. Make sure that the client you are using has exactly whitelisted the redirect_uri you specified.",
62 CodeField: http.StatusBadRequest,
63 }
64 ErrUnauthorizedClient = &RFC6749Error{
65 ErrorField: errUnauthorizedClientName,
66 DescriptionField: "The client is not authorized to request a token using this method.",
67 HintField: "Make sure that client id and secret are correctly specified and that the client exists.",
68 CodeField: http.StatusBadRequest,
69 }
70 ErrAccessDenied = &RFC6749Error{
71 ErrorField: errAccessDeniedName,
72 DescriptionField: "The resource owner or authorization server denied the request.",
73 HintField: "Make sure that the request you are making is valid. Maybe the credential or request parameters you are using are limited in scope or otherwise restricted.",
74 CodeField: http.StatusForbidden,
75 }
76 ErrUnsupportedResponseType = &RFC6749Error{
77 ErrorField: errUnsupportedResponseTypeName,
78 DescriptionField: "The authorization server does not support obtaining a token using this method.",
79 CodeField: http.StatusBadRequest,
80 }
81 ErrUnsupportedResponseMode = &RFC6749Error{
82 ErrorField: errUnsupportedResponseModeName,
83 DescriptionField: "The authorization server does not support obtaining a response using this response mode.",
84 CodeField: http.StatusBadRequest,
85 }
86 ErrInvalidScope = &RFC6749Error{
87 ErrorField: errInvalidScopeName,
88 DescriptionField: "The requested scope is invalid, unknown, or malformed.",
89 CodeField: http.StatusBadRequest,
90 }
91 ErrServerError = &RFC6749Error{
92 ErrorField: errServerErrorName,
93 DescriptionField: "The authorization server encountered an unexpected condition that prevented it from fulfilling the request.",
94 CodeField: http.StatusInternalServerError,
95 }
96 ErrTemporarilyUnavailable = &RFC6749Error{
97 ErrorField: errTemporarilyUnavailableName,
98 DescriptionField: "The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server.",
99 CodeField: http.StatusServiceUnavailable,
100 }
101 ErrUnsupportedGrantType = &RFC6749Error{
102 ErrorField: errUnsupportedGrantTypeName,
103 DescriptionField: "The authorization grant type is not supported by the authorization server.",
104 CodeField: http.StatusBadRequest,
105 }
106 ErrInvalidGrant = &RFC6749Error{
107 ErrorField: errInvalidGrantName,
108 DescriptionField: "The provided authorization grant (e.g., authorization code, resource owner credentials) or refresh token is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client.",
109 CodeField: http.StatusBadRequest,
110 }
111 ErrInvalidClient = &RFC6749Error{
112 ErrorField: errInvalidClientName,
113 DescriptionField: "Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method).",
114 CodeField: http.StatusUnauthorized,
115 }
116 ErrInvalidState = &RFC6749Error{
117 ErrorField: errInvalidStateName,
118 DescriptionField: "The state is missing or does not have enough characters and is therefore considered too weak.",
119 CodeField: http.StatusBadRequest,
120 }
121 ErrMisconfiguration = &RFC6749Error{
122 ErrorField: errMisconfigurationName,
123 DescriptionField: "The request failed because of an internal error that is probably caused by misconfiguration.",
124 CodeField: http.StatusInternalServerError,
125 }
126 ErrInsufficientEntropy = &RFC6749Error{
127 ErrorField: errInsufficientEntropyName,
128 DescriptionField: "The request used a security parameter (e.g., anti-replay, anti-csrf) with insufficient entropy.",
129 CodeField: http.StatusBadRequest,
130 }
131 ErrNotFound = &RFC6749Error{
132 ErrorField: errNotFoundName,
133 DescriptionField: "Could not find the requested resource(s).",
134 CodeField: http.StatusNotFound,
135 }
136 ErrRequestUnauthorized = &RFC6749Error{
137 ErrorField: errRequestUnauthorizedName,
138 DescriptionField: "The request could not be authorized.",
139 HintField: "Check that you provided valid credentials in the right format.",
140 CodeField: http.StatusUnauthorized,
141 }
142 ErrTokenSignatureMismatch = &RFC6749Error{
143 ErrorField: errTokenSignatureMismatchName,
144 DescriptionField: "Token signature mismatch.",
145 HintField: "Check that you provided a valid token in the right format.",
146 CodeField: http.StatusBadRequest,
147 }
148 ErrInvalidTokenFormat = &RFC6749Error{
149 ErrorField: errInvalidTokenFormatName,
150 DescriptionField: "Invalid token format.",
151 HintField: "Check that you provided a valid token in the right format.",
152 CodeField: http.StatusBadRequest,
153 }
154 ErrTokenExpired = &RFC6749Error{
155 ErrorField: errTokenExpiredName,
156 DescriptionField: "Token expired.",
157 HintField: "The token expired.",
158 CodeField: http.StatusUnauthorized,
159 }
160 ErrScopeNotGranted = &RFC6749Error{
161 ErrorField: errScopeNotGrantedName,
162 DescriptionField: "The token was not granted the requested scope.",
163 HintField: "The resource owner did not grant the requested scope.",
164 CodeField: http.StatusForbidden,
165 }
166 ErrTokenClaim = &RFC6749Error{
167 ErrorField: errTokenClaimName,
168 DescriptionField: "The token failed validation due to a claim mismatch.",
169 HintField: "One or more token claims failed validation.",
170 CodeField: http.StatusUnauthorized,
171 }
172 ErrInactiveToken = &RFC6749Error{
173 ErrorField: errTokenInactiveName,
174 DescriptionField: "Token is inactive because it is malformed, expired or otherwise invalid.",
175 HintField: "Token validation failed.",
176 CodeField: http.StatusUnauthorized,
177 }
178 ErrLoginRequired = &RFC6749Error{
179 ErrorField: errLoginRequired,
180 DescriptionField: "The Authorization Server requires End-User authentication.",
181 CodeField: http.StatusBadRequest,
182 }
183 ErrInteractionRequired = &RFC6749Error{
184 DescriptionField: "The Authorization Server requires End-User interaction of some form to proceed.",
185 ErrorField: errInteractionRequired,
186 CodeField: http.StatusBadRequest,
187 }
188 ErrConsentRequired = &RFC6749Error{
189 DescriptionField: "The Authorization Server requires End-User consent.",
190 ErrorField: errConsentRequired,
191 CodeField: http.StatusBadRequest,
192 }
193 ErrRequestNotSupported = &RFC6749Error{
194 DescriptionField: "The OP does not support use of the request parameter.",
195 ErrorField: errRequestNotSupportedName,
196 CodeField: http.StatusBadRequest,
197 }
198 ErrRequestURINotSupported = &RFC6749Error{
199 DescriptionField: "The OP does not support use of the request_uri parameter.",
200 ErrorField: errRequestURINotSupportedName,
201 CodeField: http.StatusBadRequest,
202 }
203 ErrRegistrationNotSupported = &RFC6749Error{
204 DescriptionField: "The OP does not support use of the registration parameter.",
205 ErrorField: errRegistrationNotSupportedName,
206 CodeField: http.StatusBadRequest,
207 }
208 ErrInvalidRequestURI = &RFC6749Error{
209 DescriptionField: "The request_uri in the Authorization Request returns an error or contains invalid data.",
210 ErrorField: errInvalidRequestURI,
211 CodeField: http.StatusBadRequest,
212 }
213 ErrInvalidRequestObject = &RFC6749Error{
214 DescriptionField: "The request parameter contains an invalid Request Object.",
215 ErrorField: errInvalidRequestObject,
216 CodeField: http.StatusBadRequest,
217 }
218 ErrJTIKnown = &RFC6749Error{
219 DescriptionField: "The jti was already used.",
220 ErrorField: errJTIKnownName,
221 CodeField: http.StatusBadRequest,
222 }
223 )
224
225 const (
226 errInvalidRequestURI = "invalid_request_uri"
227 errInvalidRequestObject = "invalid_request_object"
228 errConsentRequired = "consent_required"
229 errInteractionRequired = "interaction_required"
230 errLoginRequired = "login_required"
231 errRequestUnauthorizedName = "request_unauthorized"
232 errRequestForbidden = "request_forbidden"
233 errInvalidRequestName = "invalid_request"
234 errUnauthorizedClientName = "unauthorized_client"
235 errAccessDeniedName = "access_denied"
236 errUnsupportedResponseTypeName = "unsupported_response_type"
237 errUnsupportedResponseModeName = "unsupported_response_mode"
238 errInvalidScopeName = "invalid_scope"
239 errServerErrorName = "server_error"
240 errTemporarilyUnavailableName = "temporarily_unavailable"
241 errUnsupportedGrantTypeName = "unsupported_grant_type"
242 errInvalidGrantName = "invalid_grant"
243 errInvalidClientName = "invalid_client"
244 errNotFoundName = "not_found"
245 errInvalidStateName = "invalid_state"
246 errMisconfigurationName = "misconfiguration"
247 errInsufficientEntropyName = "insufficient_entropy"
248 errInvalidTokenFormatName = "invalid_token"
249 errTokenSignatureMismatchName = "token_signature_mismatch"
250 errTokenExpiredName = "invalid_token"
251 errScopeNotGrantedName = "scope_not_granted"
252 errTokenClaimName = "token_claim"
253 errTokenInactiveName = "token_inactive"
254
255 errUnknownErrorName = "error"
256 errRequestNotSupportedName = "request_not_supported"
257 errRequestURINotSupportedName = "request_uri_not_supported"
258 errRegistrationNotSupportedName = "registration_not_supported"
259 errJTIKnownName = "jti_known"
260 )
261
262 type (
263 RFC6749Error struct {
264 ErrorField string
265 DescriptionField string
266 HintField string
267 CodeField int
268 DebugField string
269 cause error
270 useLegacyFormat bool
271 exposeDebug bool
272
273
274 hintIDField string
275 hintArgs []interface{}
276 catalog i18n.MessageCatalog
277 lang language.Tag
278 }
279 stackTracer interface {
280 StackTrace() errors.StackTrace
281 }
282 )
283
284 var (
285 _ errorsx.DebugCarrier = new(RFC6749Error)
286 _ errorsx.ReasonCarrier = new(RFC6749Error)
287 _ errorsx.RequestIDCarrier = new(RFC6749Error)
288 _ errorsx.StatusCarrier = new(RFC6749Error)
289 _ errorsx.StatusCodeCarrier = new(RFC6749Error)
290
291 )
292
293 func ErrorToRFC6749Error(err error) *RFC6749Error {
294 var e *RFC6749Error
295 if errors.As(err, &e) {
296 return e
297 }
298 return &RFC6749Error{
299 ErrorField: errUnknownErrorName,
300 DescriptionField: "The error is unrecognizable",
301 DebugField: err.Error(),
302 CodeField: http.StatusInternalServerError,
303 cause: err,
304 }
305 }
306
307
308 func (e *RFC6749Error) StackTrace() (trace errors.StackTrace) {
309 if e.cause == e || e.cause == nil {
310 return
311 }
312
313 if st := stackTracer(nil); stderr.As(e.cause, &st) {
314 trace = st.StackTrace()
315 }
316
317 return
318 }
319
320 func (e RFC6749Error) Unwrap() error {
321 return e.cause
322 }
323
324 func (e *RFC6749Error) Wrap(err error) {
325 e.cause = err
326 }
327
328 func (e RFC6749Error) WithWrap(cause error) *RFC6749Error {
329 e.cause = cause
330 return &e
331 }
332
333 func (e RFC6749Error) WithLegacyFormat(useLegacyFormat bool) *RFC6749Error {
334 e.useLegacyFormat = useLegacyFormat
335 return &e
336 }
337
338 func (e *RFC6749Error) WithTrace(err error) *RFC6749Error {
339 if st := stackTracer(nil); !stderr.As(e.cause, &st) {
340 e.Wrap(errorsx.WithStack(err))
341 } else {
342 e.Wrap(err)
343 }
344 return e
345 }
346
347 func (e RFC6749Error) Is(err error) bool {
348 switch te := err.(type) {
349 case RFC6749Error:
350 return e.ErrorField == te.ErrorField &&
351 e.CodeField == te.CodeField
352 case *RFC6749Error:
353 return e.ErrorField == te.ErrorField &&
354 e.CodeField == te.CodeField
355 }
356 return false
357 }
358
359 func (e *RFC6749Error) Status() string {
360 return http.StatusText(e.CodeField)
361 }
362
363 func (e RFC6749Error) Error() string {
364 return e.ErrorField
365 }
366
367 func (e *RFC6749Error) RequestID() string {
368 return ""
369 }
370
371 func (e *RFC6749Error) Reason() string {
372 return e.HintField
373 }
374
375 func (e *RFC6749Error) StatusCode() int {
376 return e.CodeField
377 }
378
379 func (e *RFC6749Error) Cause() error {
380 return e.cause
381 }
382
383 func (e *RFC6749Error) WithHintf(hint string, args ...interface{}) *RFC6749Error {
384 err := *e
385 if err.hintIDField == "" {
386 err.hintIDField = hint
387 }
388
389 err.hintArgs = args
390 err.HintField = fmt.Sprintf(hint, args...)
391 return &err
392 }
393
394 func (e *RFC6749Error) WithHint(hint string) *RFC6749Error {
395 err := *e
396 if err.hintIDField == "" {
397 err.hintIDField = hint
398 }
399
400 err.HintField = hint
401 return &err
402 }
403
404
405 func (e *RFC6749Error) WithHintIDOrDefaultf(ID string, def string, args ...interface{}) *RFC6749Error {
406 err := *e
407 err.hintIDField = ID
408 err.hintArgs = args
409 err.HintField = fmt.Sprintf(def, args...)
410 return &err
411 }
412
413
414
415 func (e *RFC6749Error) WithHintTranslationID(ID string) *RFC6749Error {
416 err := *e
417 err.hintIDField = ID
418 return &err
419 }
420
421 func (e *RFC6749Error) Debug() string {
422 return e.DebugField
423 }
424
425 func (e *RFC6749Error) WithDebug(debug string) *RFC6749Error {
426 err := *e
427 err.DebugField = debug
428 return &err
429 }
430
431 func (e *RFC6749Error) WithDebugf(debug string, args ...interface{}) *RFC6749Error {
432 return e.WithDebug(fmt.Sprintf(debug, args...))
433 }
434
435 func (e *RFC6749Error) WithDescription(description string) *RFC6749Error {
436 err := *e
437 err.DescriptionField = description
438 return &err
439 }
440
441 func (e *RFC6749Error) WithLocalizer(catalog i18n.MessageCatalog, lang language.Tag) *RFC6749Error {
442 err := *e
443 err.catalog = catalog
444 err.lang = lang
445 return &err
446 }
447
448
449
450
451 func (e *RFC6749Error) Sanitize() *RFC6749Error {
452 err := *e
453 err.DebugField = ""
454 return &err
455 }
456
457
458 func (e *RFC6749Error) WithExposeDebug(exposeDebug bool) *RFC6749Error {
459 err := *e
460 err.exposeDebug = exposeDebug
461 return &err
462 }
463
464
465 func (e *RFC6749Error) GetDescription() string {
466 description := i18n.GetMessageOrDefault(e.catalog, e.ErrorField, e.lang, e.DescriptionField)
467 e.computeHintField()
468 if e.HintField != "" {
469 description += " " + e.HintField
470 }
471 if e.DebugField != "" && e.exposeDebug {
472 description += " " + e.DebugField
473 }
474 return strings.ReplaceAll(description, "\"", "'")
475 }
476
477
478 type RFC6749ErrorJson struct {
479 Name string `json:"error"`
480 Description string `json:"error_description"`
481 Hint string `json:"error_hint,omitempty"`
482 Code int `json:"status_code,omitempty"`
483 Debug string `json:"error_debug,omitempty"`
484 }
485
486 func (e *RFC6749Error) UnmarshalJSON(b []byte) error {
487 var data RFC6749ErrorJson
488
489 if err := json.Unmarshal(b, &data); err != nil {
490 return err
491 }
492
493 e.ErrorField = data.Name
494 e.CodeField = data.Code
495 e.DescriptionField = data.Description
496
497 if len(data.Hint+data.Debug) > 0 {
498 e.HintField = data.Hint
499 e.DebugField = data.Debug
500 e.useLegacyFormat = true
501 }
502
503 return nil
504 }
505
506 func (e RFC6749Error) MarshalJSON() ([]byte, error) {
507 if !e.useLegacyFormat {
508 return json.Marshal(&RFC6749ErrorJson{
509 Name: e.ErrorField,
510 Description: e.GetDescription(),
511 })
512 }
513
514 var debug string
515 if e.exposeDebug {
516 debug = e.DebugField
517 }
518
519 return json.Marshal(&RFC6749ErrorJson{
520 Name: e.ErrorField,
521 Description: e.DescriptionField,
522 Hint: e.HintField,
523 Code: e.CodeField,
524 Debug: debug,
525 })
526 }
527
528 func (e *RFC6749Error) ToValues() url.Values {
529 values := url.Values{}
530 values.Set("error", e.ErrorField)
531 values.Set("error_description", e.GetDescription())
532
533 if e.useLegacyFormat {
534 values.Set("error_description", e.DescriptionField)
535 if e.HintField != "" {
536 values.Set("error_hint", e.HintField)
537 }
538
539 if e.DebugField != "" && e.exposeDebug {
540 values.Set("error_debug", e.DebugField)
541 }
542 }
543
544 return values
545 }
546
547 func (e *RFC6749Error) computeHintField() {
548 if e.hintIDField == "" {
549 return
550 }
551
552 e.HintField = i18n.GetMessageOrDefault(e.catalog, e.hintIDField, e.lang, e.HintField, e.hintArgs...)
553 }
554
View as plain text