Skip to content

🧹 chore: Improve KeyAuth middleware RFC compliance#3742

Merged
ReneWerner87 merged 5 commits intomainfrom
review-keyauth-middleware-for-rfc-compliance
Sep 16, 2025
Merged

🧹 chore: Improve KeyAuth middleware RFC compliance#3742
ReneWerner87 merged 5 commits intomainfrom
review-keyauth-middleware-for-rfc-compliance

Conversation

@gaby
Copy link
Member

@gaby gaby commented Sep 12, 2025

Summary

  • use Proxy-Authenticate on 407 responses
  • validate bearer error tokens and require error_description to pair with error
  • default to an ApiKey challenge when no Authorization scheme is present
  • include optional Bearer error_uri parameter
  • advertise all configured auth schemes in WWW-Authenticate headers
  • reject tabs between auth scheme and credentials
  • support Bearer scope parameter for insufficient_scope errors
  • trim mixed leading/trailing spaces and tabs around Authorization headers
  • reject Authorization credentials containing spaces or tabs
  • validate error_uri as an absolute URI
  • validate Authorization credentials as RFC 7235 token68 strings with trailing = padding only at the end
  • enforce RFC 6750 scope-token syntax

Related #3383

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 12, 2025

Note

Other AI code review bot(s) detected

CodeRabbit 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.

Walkthrough

Adds 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

Cohort / File(s) Summary
Docs: KeyAuth
docs/middleware/keyauth.md
Documents new Config fields: Challenge, Error, ErrorDescription, ErrorURI, Scope for WWW‑Authenticate/Bearer customization.
Docs: What's New
docs/whats_new.md
Records KeyAuth API and behavior changes (new fields, extractor behavior, deferred header emission, RFC validations) and logger helper note.
KeyAuth Config & Validation
middleware/keyauth/config.go
Adds RFC‑6750 error constants (invalid_request, invalid_token, insufficient_scope); extends Config with Challenge, Error, ErrorDescription, ErrorURI, Scope; implements validation for error tokens, ErrorDescription/ErrorURI requirements, absolute ErrorURI, scope token syntax, and default ApiKey challenge when appropriate.
KeyAuth Extractors
middleware/keyauth/extractors.go
Strengthens FromAuthHeader parsing: trims header, enforces case‑insensitive scheme match and spacing rules, validates token68 characters and '=' usage, returns ErrMissingOrMalformedAPIKey on malformed input, and sets Extractor.AuthScheme.
KeyAuth Core Middleware
middleware/keyauth/keyauth.go
Aggregates schemes via getAuthSchemes, computes handler error first, then constructs per‑scheme challenges (realm, Bearer error params, scope) and sets WWW‑Authenticate or Proxy‑Authenticate header accordingly; supports multi‑scheme challenge concatenation and cfg.Challenge fallback.
Tests: Extractors
middleware/keyauth/extractors_test.go
Adds tests for leading whitespace, tab handling, internal token whitespace, and token68 character validation for FromAuthHeader.
Tests: KeyAuth
middleware/keyauth/keyauth_test.go
Adds tests for custom challenges, Bearer error params and URI, insufficient_scope and scope validation, header emission rules (401 vs 403/407), multi‑scheme headers, and config validation panics.

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
Loading
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(", ")
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • sixcolors
  • efectn
  • ReneWerner87

Poem

I nibble specs like clover sweet,
trimming tabs and tokens neat.
Realms and scopes in tidy rows,
headers bloom when status shows.
I hop through chains — challenge accepted 🥕✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The PR description enumerates many implemented RFC-related behaviors and references issue #3383, but it does not follow the repository's required template: it lacks a "Fixes #" line, the "Changes introduced" section with checklist items (benchmarks, docs, changelog, migration guide, examples), an explicit "Type of change" selection, and the completed pre-submit checklist entries, so required sections and information are missing or incomplete. Please update the PR description to match the repository template by adding a concise "Description" with "Fixes #", a "Changes introduced" section that documents documentation and changelog updates and test changes, mark the appropriate "Type of change", and complete the checklist items (benchmarks, docs, migration guidance, and examples) so reviewers have the required context for merging.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The title "🧹 chore: Improve KeyAuth middleware RFC compliance" succinctly captures the primary intent of the changeset (bringing KeyAuth into RFC compliance) and maps directly to the PR objectives and diffs, so it is fully related to the changeset; the emoji is minor noise but does not obscure the meaning.
Docstring Coverage ✅ Passed Docstring coverage is 80.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch review-keyauth-middleware-for-rfc-compliance

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.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gaby gaby changed the title feat: improve keyauth RFC compliance 🧹 chore: improve KeyAuth middleware RFC compliance Sep 12, 2025
@gaby gaby added v3 and removed ✏️ Feature labels Sep 12, 2025
@gaby gaby added this to v3 Sep 12, 2025
@gaby gaby added this to the v3 milestone Sep 12, 2025
@gaby gaby moved this to In Progress in v3 Sep 12, 2025
@gaby
Copy link
Member Author

gaby commented Sep 12, 2025

/gemini review

@codecov
Copy link

codecov bot commented Sep 12, 2025

Codecov Report

❌ Patch coverage is 99.07407% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 92.10%. Comparing base (6d7c9df) to head (7000ec1).
⚠️ Report is 188 commits behind head on main.

Files with missing lines Patch % Lines
middleware/keyauth/extractors.go 97.43% 1 Missing ⚠️
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     
Flag Coverage Δ
unittests 92.10% <99.07%> (+0.05%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

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.

@gaby gaby marked this pull request as ready for review September 12, 2025 16:31
@gaby gaby requested a review from a team as a code owner September 12, 2025 16:31
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

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

@gaby gaby changed the title 🧹 chore: improve KeyAuth middleware RFC compliance 🧹 chore: Improve KeyAuth middleware RFC compliance Sep 12, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

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.Builder which is good. However, the previous review comment suggested avoiding multiple string allocations within the loop by reusing a single builder. The current implementation already uses strings.Builder efficiently, 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

📥 Commits

Reviewing files that changed from the base of the PR and between ba701cd and 41670b7.

📒 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 via make format)
Ensure code passes golangci-lint checks (enforced via make lint)
Optimize struct field alignment using betteralign (enforced via make betteralign)
Modernize Go code using gopls modernize (enforced via make modernize)

Files:

  • middleware/keyauth/keyauth.go
  • middleware/keyauth/config.go
  • middleware/keyauth/extractors.go
  • middleware/keyauth/extractors_test.go
  • middleware/keyauth/keyauth_test.go
docs/**

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Review and update the contents of the docs folder if necessary when modifying code

Files:

  • docs/middleware/keyauth.md
  • docs/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.go
  • middleware/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 FromAuthHeader implementation 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 of extractors.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 isScopeToken function 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 getAuthSchemes function 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-Authenticate for 401 and Proxy-Authenticate for 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 getAuthSchemes properly 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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

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

📥 Commits

Reviewing files that changed from the base of the PR and between 41670b7 and 1854b65.

📒 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 via make format)
Ensure code passes golangci-lint checks (enforced via make lint)
Optimize struct field alignment using betteralign (enforced via make betteralign)
Modernize Go code using gopls modernize (enforced via make 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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

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

📥 Commits

Reviewing files that changed from the base of the PR and between 7a0a23f and 7000ec1.

📒 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 via make format)
Ensure code passes golangci-lint checks (enforced via make lint)
Optimize struct field alignment using betteralign (enforced via make betteralign)
Modernize Go code using gopls modernize (enforced via make 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.

@ReneWerner87 ReneWerner87 merged commit 7265515 into main Sep 16, 2025
15 checks passed
@ReneWerner87 ReneWerner87 deleted the review-keyauth-middleware-for-rfc-compliance branch September 16, 2025 19:53
@github-project-automation github-project-automation bot moved this from In Progress to Done in v3 Sep 16, 2025
Abhirup-99 pushed a commit to Abhirup-99/fiber that referenced this pull request Nov 3, 2025
@gaby gaby added the 📜 RFC Compliance Feature, implementation, or contribution adheres to relevant RFC standards. label Nov 27, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

codex 📜 RFC Compliance Feature, implementation, or contribution adheres to relevant RFC standards. 🧹 Updates v3

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants