🧹 chore: Improve KeyAuth middleware RFC compliance#3742
Conversation
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughAdds RFC‑6750 Bearer error fields and Challenge to KeyAuth config; introduces token68 and scope validation; tightens Authorization header parsing with token68 rules; propagates Extractor.AuthScheme and aggregates multiple schemes; defers and composes WWW‑Authenticate/Proxy‑Authenticate headers after handler outcome; updates docs and tests. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor Client
participant App as Fiber App
participant KA as KeyAuth Middleware
participant Ext as Extractor Chain
participant H as Next Handler
participant EH as Error Handler
Client->>App: HTTP Request
App->>KA: invoke KeyAuth
KA->>Ext: Extract token (chain traversal)
Ext-->>KA: token or ErrMissingOrMalformedAPIKey
alt token present & valid
KA->>H: call next handler
H-->>KA: response (maybe success/err)
else missing/invalid
KA->>EH: call error handler
EH-->>KA: handlerErr (with status)
end
KA->>KA: determine final status from handlerErr/response
alt status is 401 or 407
KA->>KA: getAuthSchemes() -> [schemes...]
KA->>KA: build per‑scheme challenges (realm + Bearer error params + scope)
KA-->>App: set WWW‑Authenticate / Proxy‑Authenticate header
else
KA-->>App: do not set auth header
end
KA-->>App: return response / handlerErr
sequenceDiagram
participant KA as KeyAuth
participant Ext as Extractor Chain
KA->>Ext: getAuthSchemes()
loop traverse chain
Ext-->>KA: AuthScheme (if any)
KA->>Ext: next extractor
end
KA-->>KA: aggregate schemes -> compose challenges -> join(", ")
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests
Tip 👮 Agentic pre-merge checks are now available in preview!Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.
Please see the documentation for more information. Example: reviews:
pre_merge_checks:
custom_checks:
- name: "Undocumented Breaking Changes"
mode: "warning"
instructions: |
Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).Please share your feedback with us on this Discord post. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
/gemini review |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #3742 +/- ##
==========================================
+ Coverage 92.05% 92.10% +0.05%
==========================================
Files 115 115
Lines 11585 11723 +138
==========================================
+ Hits 10664 10797 +133
- Misses 668 671 +3
- Partials 253 255 +2
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Code Review
This pull request significantly improves the RFC compliance of the KeyAuth middleware. It introduces stricter validation for headers and tokens, adds support for more Bearer authentication parameters, and makes the WWW-Authenticate header generation more flexible and correct. The changes are well-structured and thoroughly tested. I have one suggestion to improve performance by using strings.Builder for string concatenation in a loop. Overall, this is an excellent contribution that enhances the robustness and standards-adherence of the middleware.
There was a problem hiding this comment.
Pull Request Overview
This PR enhances the KeyAuth middleware to improve RFC compliance and authentication header handling. It adds support for proper Bearer token error responses, validates authorization credentials format, and provides better WWW-Authenticate header management.
Key changes include:
- Enhanced Bearer error handling with RFC 6750 compliant error parameters (error, error_description, error_uri, scope)
- Improved authorization header parsing with RFC 7235 token68 validation and whitespace handling
- Multiple authentication scheme support in WWW-Authenticate headers
Reviewed Changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| middleware/keyauth/keyauth.go | Refactored to support multiple auth schemes and defer WWW-Authenticate header setting until after status determination |
| middleware/keyauth/config.go | Added new configuration fields for Bearer error parameters with validation logic |
| middleware/keyauth/extractors.go | Enhanced FromAuthHeader with strict RFC compliance for token validation and whitespace handling |
| middleware/keyauth/keyauth_test.go | Added comprehensive test coverage for new features and edge cases |
| middleware/keyauth/extractors_test.go | Added tests for authorization header parsing edge cases |
| docs/whats_new.md | Updated documentation to reflect new features |
| docs/middleware/keyauth.md | Added documentation for new configuration options |
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (1)
middleware/keyauth/keyauth.go (1)
59-78: Consider the previous performance optimization suggestion.The current implementation builds challenges using
strings.Builderwhich is good. However, the previous review comment suggested avoiding multiple string allocations within the loop by reusing a single builder. The current implementation already usesstrings.Builderefficiently, so this is acceptable.
🧹 Nitpick comments (6)
middleware/keyauth/extractors.go (1)
62-68: Consider optimizing the scheme validation logic.The current implementation checks the scheme length and validity separately. This could be simplified for better readability.
-if len(authHeader) <= schemeLen || !strings.EqualFold(authHeader[:schemeLen], authScheme) { - return "", ErrMissingOrMalformedAPIKey -} -rest := authHeader[schemeLen:] -if len(rest) == 0 || rest[0] != ' ' { - return "", ErrMissingOrMalformedAPIKey -} +if !strings.HasPrefix(strings.ToLower(authHeader), strings.ToLower(authScheme)+" ") { + return "", ErrMissingOrMalformedAPIKey +} +rest := authHeader[schemeLen:]docs/whats_new.md (2)
1159-1160: Clarify 401 vs 407 header and tighten wording (mention tabs, absolute URI).Good summary. Please explicitly call out Proxy-Authenticate for 407 and keep token68/whitespace rules in one place.
Apply:
- New `Challenge`, `Error`, `ErrorDescription`, `ErrorURI`, and `Scope` fields allow customizing the `WWW-Authenticate` header, returning Bearer error details, and specifying required scopes. `ErrorURI` values are validated as absolute, a default `ApiKey` challenge is emitted when using non-Authorization extractors, Bearer `error` values are validated, credentials must conform to RFC 7235 `token68` syntax, and `scope` values are checked against RFC 6750's `scope-token` format. The header is also emitted only after the status code is finalized. + New `Challenge`, `Error`, `ErrorDescription`, `ErrorURI`, and `Scope` fields allow customizing challenge headers and Bearer error details. `ErrorURI` must be an absolute URI. Credentials in Authorization must follow RFC 7235 token68 (only trailing `=` padding) and must not contain spaces or tabs (tabs between scheme and credentials are rejected). When non-Authorization extractors are used, an `ApiKey` challenge is emitted by default. When multiple extractors are chained, all schemes are advertised in the challenge. The challenge header is emitted only after the final status is known (`WWW-Authenticate` for 401, `Proxy-Authenticate` for 407).
2089-2090: Mirror 407 behavior note in migration section.Echo the Proxy-Authenticate detail here for consistency.
- New `Challenge`, `Error`, `ErrorDescription`, `ErrorURI`, and `Scope` options let you customize challenge responses, include Bearer error parameters, and specify required scopes. `ErrorURI` values are validated as absolute, credentials containing whitespace are rejected, and when multiple authorization extractors are chained, all schemes are advertised in the `WWW-Authenticate` header. The middleware defers emitting `WWW-Authenticate` until a 401 status is final, and `FromAuthHeader` now trims surrounding whitespace. + New `Challenge`, `Error`, `ErrorDescription`, `ErrorURI`, and `Scope` options let you customize challenge responses, include Bearer error parameters, and specify required scopes. `ErrorURI` must be absolute. Authorization credentials must follow RFC 7235 token68 (only trailing `=`) and cannot contain spaces or tabs (tabs between scheme and credentials are rejected). When multiple authorization extractors are chained, all schemes are advertised. The middleware emits the challenge only after the final status is known (`WWW-Authenticate` on 401, `Proxy-Authenticate` on 407). `FromAuthHeader` also trims surrounding whitespace.middleware/keyauth/keyauth_test.go (3)
885-901: Custom challenge happy-path covered.Solid. Consider also asserting that no Bearer error params leak into non-Bearer schemes.
691-711: Add negative tests for tabs and embedded whitespace in token.Extractor rejects tabs between scheme and token and any spaces/tabs within token; add explicit cases.
Example additions:
func Test_HeaderSchemeTabBetweenSchemeAndToken(t *testing.T) { app := fiber.New() app.Use(New(Config{Validator: func(_ fiber.Ctx, _ string) (bool, error) { return false, ErrMissingOrMalformedAPIKey }})) app.Get("/", func(c fiber.Ctx) error { return c.SendString("OK") }) req := httptest.NewRequest(fiber.MethodGet, "/", nil) req.Header.Add("Authorization", "Bearer\t"+CorrectKey) res, err := app.Test(req) require.NoError(t, err) require.Equal(t, http.StatusUnauthorized, res.StatusCode) } func Test_HeaderSchemeSpaceInsideToken(t *testing.T) { app := fiber.New() app.Use(New(Config{Validator: func(_ fiber.Ctx, _ string) (bool, error) { return false, ErrMissingOrMalformedAPIKey }})) app.Get("/", func(c fiber.Ctx) error { return c.SendString("OK") }) req := httptest.NewRequest(fiber.MethodGet, "/", nil) req.Header.Add("Authorization", "Bearer to ken") res, err := app.Test(req) require.NoError(t, err) require.Equal(t, http.StatusUnauthorized, res.StatusCode) }Also applies to: 713-784
552-585: Add token68 padding edge cases.Cover acceptance of trailing '=' padding and rejection of '=' in the middle.
Example additions:
func Test_HeaderSchemeToken68PaddingAccepted(t *testing.T) { app := fiber.New() app.Use(New(Config{ Validator: func(_ fiber.Ctx, key string) (bool, error) { return key == "abc==" , nil }, })) app.Get("/", func(c fiber.Ctx) error { return c.SendString("OK") }) req := httptest.NewRequest(fiber.MethodGet, "/", nil) req.Header.Add("Authorization", "Bearer abc==") res, err := app.Test(req) require.NoError(t, err) require.Equal(t, http.StatusOK, res.StatusCode) } func Test_HeaderSchemeToken68EqualsInMiddleRejected(t *testing.T) { app := fiber.New() app.Use(New(Config{Validator: func(_ fiber.Ctx, _ string) (bool, error) { return false, ErrMissingOrMalformedAPIKey }})) app.Get("/", func(c fiber.Ctx) error { return c.SendString("OK") }) req := httptest.NewRequest(fiber.MethodGet, "/", nil) req.Header.Add("Authorization", "Bearer ab=c") res, err := app.Test(req) require.NoError(t, err) require.Equal(t, http.StatusUnauthorized, res.StatusCode) }Also applies to: 587-633, 646-654
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
docs/middleware/keyauth.md(1 hunks)docs/whats_new.md(2 hunks)middleware/keyauth/config.go(3 hunks)middleware/keyauth/extractors.go(1 hunks)middleware/keyauth/extractors_test.go(1 hunks)middleware/keyauth/keyauth.go(4 hunks)middleware/keyauth/keyauth_test.go(4 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
**/*.go: Format Go code using gofumpt (enforced viamake format)
Ensure code passes golangci-lint checks (enforced viamake lint)
Optimize struct field alignment using betteralign (enforced viamake betteralign)
Modernize Go code using gopls modernize (enforced viamake modernize)
Files:
middleware/keyauth/keyauth.gomiddleware/keyauth/config.gomiddleware/keyauth/extractors.gomiddleware/keyauth/extractors_test.gomiddleware/keyauth/keyauth_test.go
docs/**
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Review and update the contents of the
docsfolder if necessary when modifying code
Files:
docs/middleware/keyauth.mddocs/whats_new.md
🧠 Learnings (3)
📚 Learning: 2024-09-25T15:57:10.221Z
Learnt from: sixcolors
PR: gofiber/fiber#3016
File: middleware/csrf/csrf_test.go:188-193
Timestamp: 2024-09-25T15:57:10.221Z
Learning: In the Fiber framework tests, using `ctx.Response.Header.Cookie` may not be suitable for parsing cookies from the response header, as it requires a `*Cookie` and fills it rather than returning a string value; thus, manual parsing of the `Set-Cookie` header may be necessary.
Applied to files:
middleware/keyauth/extractors_test.gomiddleware/keyauth/keyauth_test.go
📚 Learning: 2024-10-08T19:06:06.583Z
Learnt from: dave-gray101
PR: gofiber/fiber#3027
File: docs/api/middleware/keyauth.md:222-222
Timestamp: 2024-10-08T19:06:06.583Z
Learning: The `KeyLookup` field in the `keyauth` middleware does not support pipe-delimited keys. Instead, it specifies a single source and name for key extraction, with additional sources specified in the `FallbackKeyLookups` field.
Applied to files:
docs/whats_new.md
📚 Learning: 2025-07-27T17:28:53.403Z
Learnt from: sixcolors
PR: gofiber/fiber#3625
File: middleware/session/config.go:57-58
Timestamp: 2025-07-27T17:28:53.403Z
Learning: In the session middleware `Config` struct, the `Extractor` field uses function closures (like `FromCookie(key)`), making it impossible to introspect extractor parameters at runtime for validation purposes without complex reflection techniques.
Applied to files:
middleware/keyauth/keyauth_test.go
🧬 Code graph analysis (3)
middleware/keyauth/keyauth.go (3)
middleware/keyauth/extractors.go (3)
Extractor(41-47)Source(11-11)Chain(231-272)app.go (2)
ErrorHandler(59-59)Error(62-65)constants.go (4)
StatusUnauthorized(74-74)StatusProxyAuthRequired(80-80)HeaderWWWAuthenticate(166-166)HeaderProxyAuthenticate(164-164)
middleware/keyauth/extractors.go (1)
middleware/keyauth/keyauth.go (1)
ErrMissingOrMalformedAPIKey(21-21)
middleware/keyauth/keyauth_test.go (3)
middleware/keyauth/keyauth.go (2)
New(24-87)ErrMissingOrMalformedAPIKey(21-21)middleware/keyauth/extractors.go (4)
Extractor(41-47)FromQuery(207-219)Chain(231-272)FromAuthHeader(51-104)constants.go (6)
StatusUnauthorized(74-74)StatusForbidden(76-76)HeaderWWWAuthenticate(166-166)HeaderAuthorization(163-163)StatusProxyAuthRequired(80-80)HeaderProxyAuthenticate(164-164)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: repeated
- GitHub Check: Compare
🔇 Additional comments (26)
middleware/keyauth/extractors.go (1)
54-98: LGTM! Excellent RFC compliance improvements for token validation.The enhanced
FromAuthHeaderimplementation correctly:
- Trims leading/trailing spaces and tabs from the header
- Enforces proper spacing between scheme and token (rejecting tabs)
- Validates token characters against RFC 7235 token68 specification
- Handles '=' padding correctly (only at the end, not as first character)
middleware/keyauth/extractors_test.go (3)
177-209: LGTM! Comprehensive test coverage for whitespace handling.The tests properly verify:
- Leading spaces and tabs are trimmed
- Trailing spaces and tabs are handled correctly
- Mixed whitespace patterns are accepted
204-208: Verify if trailing whitespace in the header value should be handled.The test shows that
"Bearer token4 \t "extracts "token4", but the header trimming at line 54 ofextractors.go(strings.Trim(c.Get(header), " \t")) should remove the trailing whitespace from the entire header value before processing. After the Bearer scheme and token extraction, "token4" would be extracted without any trailing whitespace.This test case appears to be testing that the implementation correctly handles trailing whitespace in the full header value, which is good.
243-289: LGTM! Thorough validation of RFC 7235 token68 character rules.The test cases effectively validate:
- Allowed characters (A-Z, a-z, 0-9, -, ., _, ~, +, /, =)
- Invalid tokens starting with '='
- Invalid tokens with '=' in the middle
- Valid tokens with trailing '=' padding
- Invalid tokens containing commas or semicolons
middleware/keyauth/config.go (4)
11-15: LGTM! Well-defined RFC 6750 error token constants.The error token constants align perfectly with RFC 6750 Section 3.1 for Bearer token error responses.
46-80: LGTM! Comprehensive RFC 6750 Bearer challenge fields.The new configuration fields provide excellent support for RFC 6750 Bearer error responses, allowing customization of:
- Custom challenge when no auth scheme is present
- Error codes and descriptions
- Error URIs for additional information
- Scope requirements for insufficient_scope errors
The documentation clearly explains the requirements and relationships between fields.
131-161: LGTM! Robust validation of RFC compliance.The validation logic correctly enforces:
- Error token must be one of the allowed values
- ErrorDescription and ErrorURI require Error to be set
- ErrorURI must be an absolute URI
- Scope is required when Error is insufficient_scope
- Scope tokens are validated for RFC 6750 compliance
165-173: LGTM! Correct RFC 6750 scope-token validation.The
isScopeTokenfunction properly validates scope tokens according to RFC 6750 Section 3, ensuring:
- Only ASCII printable characters (0x21-0x7E)
- No quotes or backslashes
- Non-empty tokens
docs/middleware/keyauth.md (1)
266-270: LGTM! Clear documentation of new RFC 6750 configuration fields.The documentation clearly explains the new Bearer challenge configuration options and their relationships, making it easy for users to understand how to properly configure RFC-compliant error responses.
middleware/keyauth/keyauth.go (3)
28-29: LGTM! Clean implementation of multi-scheme support.The
getAuthSchemesfunction efficiently collects all authentication schemes from the extractor chain, enabling proper multi-scheme WWW-Authenticate header generation.
49-83: LGTM! Proper header emission after status determination.The implementation correctly:
- Executes the error handler first to determine the response status
- Uses
WWW-Authenticatefor 401 andProxy-Authenticatefor 407- Constructs proper Bearer challenges with RFC 6750 error parameters
- Joins multiple challenges with commas as per RFC 7235
99-111: LGTM! Recursive scheme extraction handles nested chains well.The recursive implementation of
getAuthSchemesproperly traverses the entire extractor chain to collect all authentication schemes.middleware/keyauth/keyauth_test.go (14)
19-19: Good: token68-legal test token.Covers '.', '/', '~', '+', '_' ensuring extractor charset validation is exercised.
817-826: WWW-Authenticate defaults look correct.Switch to default ApiKey challenge for non-Authorization extractors matches code-path via getAuthSchemes.
Also applies to: 856-858
903-921: Bearer error fields: great coverage.Validates error, description, and error_uri formatting.
923-940: Bearer error_uri-only case covered.Looks good.
942-959: insufficient_scope behavior verified.Header includes scope only for this error. Good.
961-991: Config validation panics well tested.All three invariants are exercised.
993-1011: Header emission gated on 401 only.Good safeguard; confirms no challenge on 403.
1013-1025: Default ApiKey challenge for non-Authorization extractor.Matches intended defaulting.
1027-1042: Multiple challenges combined correctly.Order reflects extractor chain; fine.
1044-1061: Proxy-Authenticate on 407 verified.Also ensures WWW-Authenticate is absent. Nice.
1063-1070: Invalid Bearer error token panics.Covers config gate.
1072-1079: error_description requires error: covered.Good.
1081-1088: error_uri requires error: covered.Good.
1090-1098: error_uri must be absolute: covered.Good.
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
middleware/keyauth/extractors.go (1)
9-14: Spec-correct token68 helper—nice extraction.Char set matches RFC 7235 token68 and resolves the previous readability ask to extract a helper.
🧹 Nitpick comments (1)
middleware/keyauth/extractors.go (1)
88-101: Avoid shadowing c (fiber.Ctx) with a byte variable.Renaming improves readability and avoids accidental confusion.
- for j := 0; j < len(token); j++ { - c := token[j] - if !isToken68Char(c) { + for j := 0; j < len(token); j++ { + ch := token[j] + if !isToken68Char(ch) { return "", ErrMissingOrMalformedAPIKey } - if c == '=' { + if ch == '=' { if j == 0 { return "", ErrMissingOrMalformedAPIKey } seenEq = true - } else if seenEq { + } else if seenEq { return "", ErrMissingOrMalformedAPIKey } }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
middleware/keyauth/extractors.go(2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
**/*.go: Format Go code using gofumpt (enforced viamake format)
Ensure code passes golangci-lint checks (enforced viamake lint)
Optimize struct field alignment using betteralign (enforced viamake betteralign)
Modernize Go code using gopls modernize (enforced viamake modernize)
Files:
middleware/keyauth/extractors.go
🧬 Code graph analysis (1)
middleware/keyauth/extractors.go (1)
middleware/keyauth/keyauth.go (1)
ErrMissingOrMalformedAPIKey(21-21)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Compare
- GitHub Check: repeated
- GitHub Check: unit (1.25.x, windows-latest)
🔇 Additional comments (1)
middleware/keyauth/extractors.go (1)
107-110: Propagating AuthScheme on Extractor enables per-scheme advertisement. LGTM.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
middleware/keyauth/keyauth.go (3)
80-83: Don’t overwrite an auth header already set by the ErrorHandler.Respect a pre-set header by appending, otherwise set it.
- c.Set(header, strings.Join(challenges, ", ")) + v := strings.Join(challenges, ", ") + if len(c.Response().Header.Peek(header)) == 0 { + c.Set(header, v) + } else { + c.Append(header, v) + } - } else if cfg.Challenge != "" { - c.Set(header, cfg.Challenge) + } else if cfg.Challenge != "" { + if len(c.Response().Header.Peek(header)) == 0 { + c.Set(header, cfg.Challenge) + } else { + c.Append(header, cfg.Challenge) + } }
62-76: Avoid fmt.Fprintf in hot path; use WriteString + strconv.Quote.Trim fmt overhead while keeping safe quoting.
- var b strings.Builder - fmt.Fprintf(&b, "%s realm=%q", scheme, cfg.Realm) + var b strings.Builder + b.WriteString(scheme) + b.WriteString(" realm=") + b.WriteString(strconv.Quote(cfg.Realm)) if utils.EqualFold(scheme, "Bearer") { if cfg.Error != "" { - fmt.Fprintf(&b, ", error=%q", cfg.Error) + b.WriteString(", error=") + b.WriteString(strconv.Quote(cfg.Error)) if cfg.ErrorDescription != "" { - fmt.Fprintf(&b, ", error_description=%q", cfg.ErrorDescription) + b.WriteString(", error_description=") + b.WriteString(strconv.Quote(cfg.ErrorDescription)) } if cfg.ErrorURI != "" { - fmt.Fprintf(&b, ", error_uri=%q", cfg.ErrorURI) + b.WriteString(", error_uri=") + b.WriteString(strconv.Quote(cfg.ErrorURI)) } if cfg.Error == ErrorInsufficientScope { - fmt.Fprintf(&b, ", scope=%q", cfg.Scope) + b.WriteString(", scope=") + b.WriteString(strconv.Quote(cfg.Scope)) } } }Also update imports:
-import ( - "errors" - "fmt" - "strings" +import ( + "errors" + "strconv" + "strings"
100-112: Deduplicate advertised schemes; preserve order.If the chain repeats the same SourceAuthHeader scheme, the header will list duplicates.
-func getAuthSchemes(e Extractor) []string { - var schemes []string - if e.Source == SourceAuthHeader && e.AuthScheme != "" { - schemes = append(schemes, e.AuthScheme) - } - for _, ex := range e.Chain { - schemes = append(schemes, getAuthSchemes(ex)...) - } - return schemes -} +func getAuthSchemes(e Extractor) []string { + schemes := make([]string, 0, 4) + seen := make(map[string]struct{}, 4) + var walk func(Extractor) + walk = func(ex Extractor) { + if ex.Source == SourceAuthHeader && ex.AuthScheme != "" { + if _, ok := seen[ex.AuthScheme]; !ok { + seen[ex.AuthScheme] = struct{}{} + schemes = append(schemes, ex.AuthScheme) + } + } + for _, ch := range ex.Chain { + walk(ch) + } + } + walk(e) + return schemes +}
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
middleware/keyauth/extractors.go(2 hunks)middleware/keyauth/keyauth.go(4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- middleware/keyauth/extractors.go
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
**/*.go: Format Go code using gofumpt (enforced viamake format)
Ensure code passes golangci-lint checks (enforced viamake lint)
Optimize struct field alignment using betteralign (enforced viamake betteralign)
Modernize Go code using gopls modernize (enforced viamake modernize)
Files:
middleware/keyauth/keyauth.go
🧬 Code graph analysis (1)
middleware/keyauth/keyauth.go (3)
middleware/keyauth/extractors.go (3)
Extractor(49-55)Source(19-19)Chain(239-280)constants.go (4)
StatusUnauthorized(74-74)StatusProxyAuthRequired(80-80)HeaderWWWAuthenticate(166-166)HeaderProxyAuthenticate(164-164)middleware/keyauth/config.go (1)
ErrorInsufficientScope(14-14)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Compare
- GitHub Check: unit (1.25.x, windows-latest)
- GitHub Check: unit (1.25.x, macos-latest)
- GitHub Check: repeated
🔇 Additional comments (3)
middleware/keyauth/keyauth.go (3)
3-10: Imports look good.strings is used for Builder/join; utils.EqualFold usage is consistent with the rest of Fiber utils.
29-31: Confirm extractor immutability or compute schemes lazily.authSchemes is captured once at New() time. If cfg.Extractor (or its Chain) can be mutated after middleware construction, the advertised challenges may become stale. If mutability is possible, compute on demand or cache on first use.
50-54: No action required — ErrorHandler sets status before challenges are attached.
Default ErrorHandler in middleware/keyauth/config.go returns c.Status(fiber.StatusUnauthorized) (401); tests in middleware/keyauth/keyauth_test.go verify WWW-Authenticate/Proxy-Authenticate are set for 401/407 and omitted for 403.
Summary
Proxy-Authenticateon 407 responseserror_descriptionto pair witherrorApiKeychallenge when no Authorization scheme is presenterror_uriparameterWWW-Authenticateheadersscopeparameter forinsufficient_scopeerrorserror_urias an absolute URI=padding only at the endRelated #3383