Skip to content

Refactor KeyAuth Middleware: Extractor-Based Configuration and Enhanced Flexibility#3685

Merged
ReneWerner87 merged 4 commits intomainfrom
keyauth-extractors
Aug 14, 2025
Merged

Refactor KeyAuth Middleware: Extractor-Based Configuration and Enhanced Flexibility#3685
ReneWerner87 merged 4 commits intomainfrom
keyauth-extractors

Conversation

@sixcolors
Copy link
Member

Description

This PR modernizes the keyauth middleware by replacing the legacy string-based key extraction configuration (KeyLookup, AuthScheme, CustomKeyLookup) with a robust, type-safe extractor system. This update improves flexibility, composability, and clarity for users implementing API key authentication in Fiber.

Key Changes

  • Extractor-Based API Key Retrieval:

    • Introduces a new Extractor field for configuration, allowing explicit selection of where to extract the API key (header, auth header, query, param, cookie, form).
    • Provides helper functions:
      • FromHeader(header string)
      • FromAuthHeader(header, scheme string)
      • FromCookie(name string)
      • FromQuery(param string)
      • FromParam(param string)
      • FromForm(name string)
      • Chain(...) for chaining multiple extractors.
  • Config Refactoring:

    • Removes KeyLookup, AuthScheme, and CustomKeyLookup.
    • Makes Validator required; panics if missing.
    • Updates default error handling for missing/invalid keys.
  • WWW-Authenticate Header and Realm:

    • Automatically sets the WWW-Authenticate header on authentication failure when using an auth header extractor.
    • Adds configurable Realm support.
  • Comprehensive Tests and Documentation:

    • Adds new tests covering all extractors, chaining, and error scenarios.
    • Updates docs to explain new extractor usage, migration steps, and typical patterns.

Migration Guide

Before:

app.Use(keyauth.New(keyauth.Config{
    KeyLookup: "header:Authorization",
    AuthScheme: "Bearer",
    Validator: validateAPIKey,
}))

After:

app.Use(keyauth.New(keyauth.Config{
    Extractor: keyauth.FromAuthHeader(fiber.HeaderAuthorization, "Bearer"),
    Validator: validateAPIKey,
}))

You can combine multiple sources:

app.Use(keyauth.New(keyauth.Config{
    Extractor: keyauth.Chain(
        keyauth.FromHeader("X-API-Key"),
        keyauth.FromQuery("api_key"),
    ),
    Validator: validateAPIKey,
}))

Why?

  • Type Safety & Extensibility:
    Explicit extractor configuration avoids fragile string parsing and makes it easier to extend/customize key source logic.
  • Composability:
    Easily combine multiple sources for API key retrieval using Chain.
  • Clearer Error Handling:
    Consistent error messages and WWW-Authenticate support.
  • Cleaner Configuration:
    No ambiguous string formats; everything is explicit and documented.

Breaking Changes:

  • KeyLookup, AuthScheme, and CustomKeyLookup have been removed.
  • You must use the new Extractor configuration with provided helper functions.

See updated documentation and migration notes for further details.

…pdate Error Handling

- Refactored key extraction logic in extractors.go to improve clarity and maintainability.
- Added comprehensive unit tests for all extractors, ensuring correct behavior for missing and valid API keys.
- Updated error messages for better clarity and consistency across the middleware.
- Introduced a new WWW-Authenticate header feature for improved API security compliance.
- Enhanced test coverage for configuration defaults and custom configurations in config_test.go.
- Improved handling of multiple key sources in keyauth_test.go, ensuring robust validation and extraction.
Copilot AI review requested due to automatic review settings August 14, 2025 16:11
@sixcolors sixcolors requested a review from a team as a code owner August 14, 2025 16:11
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 14, 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

Refactors KeyAuth middleware from KeyLookup/AuthScheme to an Extractor/Validator model with chaining and per-source missing-key errors, updates default config and error handling, sets WWW-Authenticate using realm and scheme, and revises docs (including EncryptCookie key length and CSRF examples). Adds new extractor implementations and comprehensive tests.

Changes

Cohort / File(s) Summary of Changes
Documentation updates
docs/middleware/encryptcookie.md, docs/middleware/keyauth.md, docs/whats_new.md
Updated EncryptCookie key length guidance and base64 note; migrated KeyAuth docs to Extractor/Validator with chaining and realm; added CSRF extractor guidance (use header/form/query; remove cookie-based extraction) and migration notes.
KeyAuth configuration and core flow
middleware/keyauth/config.go, middleware/keyauth/keyauth.go
Removed KeyLookup/AuthScheme APIs; added Extractor, Validator, Realm; default Extractor set to FromAuthHeader with Bearer; granular ErrorHandler; middleware now extracts via Extractor, validates, sets WWW-Authenticate on failure; removed legacy key-lookup helpers.
Extractor subsystem
middleware/keyauth/extractors.go
Introduced Extractor struct, Source enum, per-source missing-key errors; added constructors: FromHeader, FromAuthHeader, FromQuery, FromParam, FromCookie, FromForm; added Chain to compose extractors.
Tests
middleware/keyauth/config_test.go, middleware/keyauth/extractors_test.go, middleware/keyauth/keyauth_test.go
Added/updated tests for config defaults/panics, extractor behaviors and errors, chaining logic, and WWW-Authenticate header behavior with new API.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Client
  participant FiberApp
  participant KeyAuth as KeyAuth Middleware
  participant Extractor
  participant Validator
  participant ErrorHandler

  Client->>FiberApp: HTTP Request
  FiberApp->>KeyAuth: Invoke middleware
  KeyAuth->>Extractor: Extract(c)
  alt Key found
    KeyAuth->>Validator: Validate(c, key)
    alt Valid
      KeyAuth-->>FiberApp: SuccessHandler / next
    else Invalid/expired
      KeyAuth->>KeyAuth: Set WWW-Authenticate (scheme, realm)
      KeyAuth->>ErrorHandler: Handle invalid
      ErrorHandler-->>FiberApp: 401 response
    end
  else Missing key
    KeyAuth->>KeyAuth: Set WWW-Authenticate (scheme, realm)
    KeyAuth->>ErrorHandler: Handle missing (per-source error)
    ErrorHandler-->>FiberApp: 401 response
  end
Loading
sequenceDiagram
  autonumber
  participant C as Context
  participant Chain as Chain(Extractor...)
  participant E1 as Extractor #1
  participant E2 as Extractor #2
  participant E3 as Extractor #3

  C->>Chain: Extract(c)
  Chain->>E1: Extract(c)
  alt E1 fails
    Chain->>E2: Extract(c)
    alt E2 fails
      Chain->>E3: Extract(c)
      alt E3 fails
        Chain-->>C: Return last error
      else
        Chain-->>C: Return key from E3
      end
    else
      Chain-->>C: Return key from E2
    end
  else
    Chain-->>C: Return key from E1
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

✏️ Feature, v3

Suggested reviewers

  • gaby
  • ReneWerner87
  • efectn

Poem

I hop through headers, query strings, and form—
A chain of carrots leads me past the storm.
“Bearer,” whispers wind; “Restricted,” skies proclaim,
I sniff the key, then validate the claim.
If crumbs are missing—401 I thump! 🥕
Next trail found, I bounce—security jump!

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch keyauth-extractors

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

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.

Summary of Changes

Hello @sixcolors, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly refactors the keyauth middleware in Fiber, transitioning from a string-based API key extraction mechanism to a more modern, type-safe, and flexible extractor system. The primary goal is to enhance the clarity, extensibility, and composability of API key authentication configurations. This change simplifies how developers specify API key sources and improves error handling, making the middleware more robust and easier to use.

Highlights

  • Extractor-Based API Key Retrieval: Introduces a new Extractor field in the keyauth.Config struct, allowing explicit definition of how API keys are retrieved (e.g., from headers, query parameters, cookies, form data, or path parameters).
  • Helper Functions for Extractors: Provides a set of built-in helper functions like FromHeader, FromAuthHeader, FromCookie, FromQuery, FromParam, and FromForm to easily configure the Extractor.
  • Extractor Chaining: Adds keyauth.Chain to combine multiple extractors, allowing the middleware to try different sources for the API key in a defined order.
  • Configuration Simplification and Enforcement: Removes the legacy KeyLookup, AuthScheme, and CustomKeyLookup fields. The Validator function is now explicitly required, and the middleware will panic if it's not provided.
  • Enhanced Error Handling and WWW-Authenticate Header: Updates default error handling for missing/invalid keys and automatically sets the WWW-Authenticate header on authentication failure when an auth header extractor is used, with configurable Realm support.
  • Documentation and Test Updates: Comprehensive updates to documentation, including migration steps and examples, along with new tests covering all extractor functionalities and error scenarios.
  • Breaking Change: The removal of KeyLookup, AuthScheme, and CustomKeyLookup means existing implementations must migrate to the new Extractor configuration.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

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 modernizes the keyauth middleware by replacing the legacy string-based key extraction configuration with a type-safe extractor system. This refactor improves developer experience through explicit configuration and enables flexible composition of multiple extraction sources.

Key Changes

  • Introduces a new Extractor field with helper functions like FromHeader, FromAuthHeader, FromCookie, and Chain for type-safe API key extraction
  • Removes deprecated KeyLookup, AuthScheme, and CustomKeyLookup fields in favor of the extractor system
  • Adds automatic WWW-Authenticate header setting on authentication failure when using auth header extractors

Reviewed Changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
middleware/keyauth/keyauth.go Core middleware logic updated to use extractor system and handle WWW-Authenticate headers
middleware/keyauth/config.go Configuration refactored to require Validator and use Extractor instead of string-based lookups
middleware/keyauth/extractors.go New file implementing type-safe extractor functions and chaining logic
middleware/keyauth/keyauth_test.go Comprehensive test updates covering all extraction methods and error scenarios
middleware/keyauth/extractors_test.go New tests specifically for extractor functionality and chaining behavior
middleware/keyauth/config_test.go New tests for configuration validation and default value handling
docs/middleware/keyauth.md Updated documentation with migration guide and extractor usage examples
docs/whats_new.md Added migration notes for the breaking changes
docs/middleware/encryptcookie.md Minor documentation update referencing new extractor syntax

You can also share your feedback on Copilot code review for a chance to win a $100 gift card. Take the survey.

expectedCode = 404
expectedBody = "Cannot GET /"
}
require.Equal(t, expectedCode, res.StatusCode, test.description)
Copy link

Copilot AI Aug 14, 2025

Choose a reason for hiding this comment

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

The variable body is used in the next line but is never declared or assigned in this scope. This will cause a compilation error.

Copilot uses AI. Check for mistakes.
Copy link
Member Author

Choose a reason for hiding this comment

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

it's on line 168

req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
}

res, err := app.Test(req, testConfig)
Copy link

Copilot AI Aug 14, 2025

Choose a reason for hiding this comment

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

The variable body is read from the response but is never assigned. The body, err := io.ReadAll(res.Body) statement appears to be missing before line 196 where body is used.

Copilot uses AI. Check for mistakes.
Copy link
Member Author

Choose a reason for hiding this comment

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

it's on line 168

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 is an excellent and comprehensive refactoring of the keyauth middleware. The move from a string-based KeyLookup to a type-safe, composable Extractor system is a significant improvement in terms of flexibility, clarity, and extensibility. The changes are well-supported by thorough updates to documentation and a robust new test suite that covers the new extractors, chaining, and error scenarios. Making the Validator a required field and enhancing the error handling with automatic WWW-Authenticate headers are also great additions that improve the middleware's usability and security posture. Overall, this is a high-quality contribution that modernizes the middleware effectively.

@codecov
Copy link

codecov bot commented Aug 14, 2025

Codecov Report

❌ Patch coverage is 99.09910% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 91.98%. Comparing base (de2ed84) to head (6116e75).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
middleware/keyauth/extractors.go 98.75% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3685      +/-   ##
==========================================
+ Coverage   91.91%   91.98%   +0.07%     
==========================================
  Files         113      114       +1     
  Lines       11496    11494       -2     
==========================================
+ Hits        10566    10573       +7     
+ Misses        667      661       -6     
+ Partials      263      260       -3     
Flag Coverage Δ
unittests 91.98% <99.09%> (+0.07%) ⬆️

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.

sixcolors and others added 3 commits August 14, 2025 13:14
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
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: 4

♻️ Duplicate comments (1)
middleware/keyauth/extractors_test.go (1)

161-161: Update the comment to match the actual error being tested.

The comment mentions ErrTokenNotFound, but the test is actually checking for ErrMissingAPIKey. Update the comment to reflect what's being tested.

-	// All extractors find nothing (return empty string and nil error), should return ErrMissingAPIKey
+	// All extractors find nothing (return empty string and nil error), should return ErrMissingAPIKey
🧹 Nitpick comments (12)
middleware/keyauth/extractors.go (3)

165-176: Trim header values to avoid false negatives due to incidental whitespace

Headers can contain incidental whitespace from proxies/clients. Trimming improves robustness and makes behavior consistent with FromAuthHeader.

-			apiKey := c.Get(param)
+			apiKey := strings.TrimSpace(c.Get(param))
 			if apiKey == "" {
 				return "", ErrMissingAPIKeyInHeader
 			}
 			return apiKey, nil

211-252: Propagate AuthScheme metadata in Chain to support WWW-Authenticate

keyauth.New derives the auth scheme via getAuthScheme(cfg.Extractor). If Extractor is a chain, setting AuthScheme from the first extractor helps consumers that don't—or can't—introspect Chain recursively.

 	return Extractor{
 		Extract: func(c fiber.Ctx) (string, error) {
 			var lastErr error
@@
 		},
-		Source: primarySource,
-		Key:    primaryKey,
-		Chain:  extractors,
+		Source:     primarySource,
+		Key:        primaryKey,
+		AuthScheme: extractors[0].AuthScheme,
+		Chain:      extractors,
 	}

41-48: Optional: Introduce an ExtractorFunc type for readability and consistency

Defining a named function type improves readability and makes signatures self-documenting.

 type Extractor struct {
-	Extract    func(fiber.Ctx) (string, error)
+	Extract    func(fiber.Ctx) (string, error)
 	Key        string      // The parameter/header name used for extraction
 	AuthScheme string      // The auth scheme, e.g., "Bearer" for AuthHeader
 	Chain      []Extractor // For chaining multiple extractors
 	Source     Source      // The type of source being extracted from
 }

Outside this range, consider:

// near the top of the file
type ExtractorFunc func(fiber.Ctx) (string, error)

// and then in Extractor:
Extract ExtractorFunc
docs/middleware/encryptcookie.md (1)

59-62: Clarify “bytes” vs “characters” and base64 length to avoid misconfiguration

The note currently says “32 char key” while requiring base64-encoded keys of 16/24/32 bytes. That’s ambiguous—base64 strings are longer than the raw byte length. Recommend clarifying wording.

-To generate a 32 char key, use `openssl rand -base64 32` or `encryptcookie.GenerateKey(32)`...
+To generate a 32-byte key, use `openssl rand -base64 32` or `encryptcookie.GenerateKey(32)`. Note that the resulting base64 string will be longer than 32 characters, but decodes to 32 bytes.

As follow-up, update the example configs to use generated/base64 keys rather than human-readable placeholders:

  • In the example at Lines 39-43:
app.Use(encryptcookie.New(encryptcookie.Config{
    Key: encryptcookie.GenerateKey(32),
}))
  • In the CSRF example at Lines 92-99:
app.Use(encryptcookie.New(encryptcookie.Config{
    Key:    encryptcookie.GenerateKey(32),
    Except: []string{csrf.ConfigDefault.CookieName},
}))
middleware/keyauth/config_test.go (2)

12-20: Panic assertion is fine, but the comment misattributes the cause

The panic arises because no config is provided (len(config) == 0), not because ConfigDefault.Validator is nil. The message is the same, but consider adjusting the comment to avoid confusion.

-// The New function will call configDefault with no arguments
-// which will panic because ConfigDefault.Validator is nil.
+// The New function will call configDefault with no arguments,
+// which panics due to a missing validator in the provided config.

45-71: Preservation of custom handlers and extractor is well tested; consider adding a test for Extractor metadata

You verify the function pointer for Extract. Consider also asserting that Key, Source, and (if applicable) AuthScheme on the extractor are preserved to guard against future regressions.

If helpful, I can draft an additional test case asserting:

  • cfg.Extractor.Key == "X-API-Key"
  • cfg.Extractor.Source == SourceHeader
docs/whats_new.md (2)

1096-1096: EncryptCookie key requirements—align wording across docs

This statement is good, but ensure consistency with encryptcookie.md (clarify “bytes” vs “characters” and base64 length). See my suggestion there.


1943-1963: Add a chaining example to demonstrate multi-source fallbacks

Consider adding a short example showing keyauth.Chain(...), which many users will reach for during migration.

Example to append below the “After” block:

// After (multiple fallbacks)
app.Use(keyauth.New(keyauth.Config{
    Extractor: keyauth.Chain(
        keyauth.FromAuthHeader(fiber.HeaderAuthorization, "Bearer"),
        keyauth.FromHeader("X-API-Key"),
        keyauth.FromQuery("api_key"),
    ),
    Validator: validateAPIKey,
}))
middleware/keyauth/extractors_test.go (1)

92-98: Consider consistently releasing contexts immediately after use within the same test.

While deferring the release is safe, you're acquiring multiple contexts within the same test function. For clarity and to avoid potential context pool exhaustion in larger tests, consider releasing each context immediately after use instead of deferring.

 	// FromQuery
 	ctx = app.AcquireCtx(&fasthttp.RequestCtx{})
-	defer app.ReleaseCtx(ctx)
 	ctx.Request().SetRequestURI("/?api_key=token_from_query")
 	token, err = FromQuery("api_key").Extract(ctx)
 	require.NoError(t, err)
 	require.Equal(t, "token_from_query", token)
+	app.ReleaseCtx(ctx)

Apply similar changes to lines 100-106, 108-114, and 116-122.

docs/middleware/keyauth.md (2)

216-220: Security consideration: Remove hardcoded API key from documentation.

The example contains a hardcoded API key in the curl command. While this is for demonstration purposes, it's better practice to use placeholder values in documentation to avoid accidentally exposing real credentials.

 # /allowed needs to be authenticated
-curl --header "Authorization: Bearer my-super-secret-key"  http://localhost:3000/allowed
+curl --header "Authorization: Bearer <your-api-key>"  http://localhost:3000/allowed
 #> Successfully authenticated!

263-263: Grammar issue in the documentation table.

There's a minor grammar issue in the description column.

-| Validator       | `func(fiber.Ctx, string) (bool, error)`  | **Required.** Validator is a function to validate the key.                                                           | `nil` (panic) |
+| Validator       | `func(fiber.Ctx, string) (bool, error)`  | **Required.** Validator is a function to validate the key.                                                           | `nil` (will panic) |
middleware/keyauth/keyauth.go (1)

67-79: Consider documenting the auth scheme detection behavior.

The getAuthScheme function searches both the top-level extractor and any chained extractors for an auth header source. This behavior should be documented to clarify that only the first found auth scheme is used.

 // getAuthScheme inspects an extractor and its chain to find the auth scheme
-// used by FromAuthHeader. It returns the scheme, or an empty string if not found.
+// used by FromAuthHeader. It returns the first auth scheme found, or an empty string if none is found.
+// When multiple FromAuthHeader extractors are chained, only the first one's scheme is used.
 func getAuthScheme(e Extractor) string {
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these settings in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between de2ed84 and 6116e75.

📒 Files selected for processing (9)
  • docs/middleware/encryptcookie.md (2 hunks)
  • docs/middleware/keyauth.md (8 hunks)
  • docs/whats_new.md (3 hunks)
  • middleware/keyauth/config.go (2 hunks)
  • middleware/keyauth/config_test.go (1 hunks)
  • middleware/keyauth/extractors.go (1 hunks)
  • middleware/keyauth/extractors_test.go (1 hunks)
  • middleware/keyauth/keyauth.go (3 hunks)
  • middleware/keyauth/keyauth_test.go (21 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
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/encryptcookie.md
  • docs/whats_new.md
  • docs/middleware/keyauth.md
🧠 Learnings (9)
📓 Common learnings
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.
Learnt from: dave-gray101
PR: gofiber/fiber#3027
File: docs/api/middleware/keyauth.md:222-222
Timestamp: 2024-06-09T18:50:02.075Z
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.
Learnt from: gaby
PR: gofiber/fiber#3056
File: middleware/encryptcookie/utils.go:20-23
Timestamp: 2024-07-01T03:44:03.672Z
Learning: Unit tests for key length enforcement in both `EncryptCookie` and `DecryptCookie` functions have been added to ensure robust validation and prevent potential runtime errors.
Learnt from: gaby
PR: gofiber/fiber#3056
File: middleware/encryptcookie/utils.go:20-23
Timestamp: 2024-10-08T19:06:06.583Z
Learning: Unit tests for key length enforcement in both `EncryptCookie` and `DecryptCookie` functions have been added to ensure robust validation and prevent potential runtime errors.
Learnt from: gaby
PR: gofiber/fiber#3056
File: middleware/encryptcookie/utils.go:51-54
Timestamp: 2024-10-08T19:06:06.583Z
Learning: Unit tests for key length enforcement in `DecryptCookie` have been added to ensure consistency and security in the encryption processes.
Learnt from: gaby
PR: gofiber/fiber#3056
File: middleware/encryptcookie/utils.go:51-54
Timestamp: 2024-07-01T03:33:22.283Z
Learning: Unit tests for key length enforcement in `DecryptCookie` have been added to ensure consistency and security in the encryption processes.
📚 Learning: 2024-07-01T03:44:03.672Z
Learnt from: gaby
PR: gofiber/fiber#3056
File: middleware/encryptcookie/utils.go:20-23
Timestamp: 2024-07-01T03:44:03.672Z
Learning: Unit tests for key length enforcement in both `EncryptCookie` and `DecryptCookie` functions have been added to ensure robust validation and prevent potential runtime errors.

Applied to files:

  • docs/middleware/encryptcookie.md
  • docs/whats_new.md
📚 Learning: 2024-10-08T19:06:06.583Z
Learnt from: gaby
PR: gofiber/fiber#3056
File: middleware/encryptcookie/utils.go:51-54
Timestamp: 2024-10-08T19:06:06.583Z
Learning: Unit tests for key length enforcement in `DecryptCookie` have been added to ensure consistency and security in the encryption processes.

Applied to files:

  • docs/middleware/encryptcookie.md
  • docs/whats_new.md
📚 Learning: 2024-10-08T19:06:06.583Z
Learnt from: gaby
PR: gofiber/fiber#3056
File: middleware/encryptcookie/utils.go:22-25
Timestamp: 2024-10-08T19:06:06.583Z
Learning: The `encryptcookie_test.go` file contains unit tests that validate key lengths for both `EncryptCookie` and `DecryptCookie` functions, ensuring that invalid key lengths raise appropriate errors.

Applied to files:

  • docs/middleware/encryptcookie.md
  • 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:

  • docs/middleware/encryptcookie.md
  • middleware/keyauth/config.go
  • middleware/keyauth/extractors.go
  • middleware/keyauth/keyauth.go
  • docs/middleware/keyauth.md
  • 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:

  • middleware/keyauth/keyauth.go
  • docs/whats_new.md
  • docs/middleware/keyauth.md
📚 Learning: 2024-10-08T19:06:06.583Z
Learnt from: sixcolors
PR: gofiber/fiber#2922
File: middleware/cors/utils.go:63-71
Timestamp: 2024-10-08T19:06:06.583Z
Learning: The project uses the testify/assert package for assertions in unit tests.

Applied to files:

  • middleware/keyauth/keyauth_test.go
📚 Learning: 2024-10-08T19:06:06.583Z
Learnt from: sixcolors
PR: gofiber/fiber#3016
File: middleware/session/store.go:164-167
Timestamp: 2024-10-08T19:06:06.583Z
Learning: Unit tests in this project use testify require.

Applied to files:

  • middleware/keyauth/keyauth_test.go
📚 Learning: 2024-12-13T08:14:22.851Z
Learnt from: efectn
PR: gofiber/fiber#3162
File: hooks_test.go:228-228
Timestamp: 2024-12-13T08:14:22.851Z
Learning: In Go test files, prefer using the `require` methods from the `testify` package for assertions instead of manual comparisons and calls to `t.Fatal` or `t.Fatalf`.

Applied to files:

  • middleware/keyauth/keyauth_test.go
🧬 Code Graph Analysis (5)
middleware/keyauth/config_test.go (3)
middleware/keyauth/keyauth.go (1)
  • New (23-55)
middleware/keyauth/config.go (2)
  • Config (10-42)
  • ConfigDefault (45-64)
middleware/keyauth/extractors.go (2)
  • Extractor (42-48)
  • FromHeader (164-176)
middleware/keyauth/extractors_test.go (1)
middleware/keyauth/extractors.go (16)
  • FromParam (118-130)
  • ErrMissingAPIKeyInParam (54-54)
  • FromForm (141-153)
  • ErrMissingAPIKeyInForm (55-55)
  • FromQuery (187-199)
  • ErrMissingAPIKeyInQuery (53-53)
  • FromHeader (164-176)
  • ErrMissingAPIKeyInHeader (52-52)
  • FromAuthHeader (61-84)
  • FromCookie (95-107)
  • ErrMissingAPIKeyInCookie (56-56)
  • Chain (211-252)
  • ErrMissingAPIKey (51-51)
  • Extractor (42-48)
  • Source (12-12)
  • SourceCustom (38-38)
middleware/keyauth/config.go (3)
middleware/keyauth/extractors.go (8)
  • Extractor (42-48)
  • ErrMissingAPIKey (51-51)
  • ErrMissingAPIKeyInHeader (52-52)
  • ErrMissingAPIKeyInQuery (53-53)
  • ErrMissingAPIKeyInParam (54-54)
  • ErrMissingAPIKeyInForm (55-55)
  • ErrMissingAPIKeyInCookie (56-56)
  • FromAuthHeader (61-84)
middleware/keyauth/keyauth.go (1)
  • ErrMissingOrMalformedAPIKey (20-20)
constants.go (2)
  • StatusUnauthorized (74-74)
  • HeaderAuthorization (163-163)
middleware/keyauth/extractors.go (2)
ctx_interface_gen.go (1)
  • Ctx (17-405)
middleware/keyauth/keyauth.go (1)
  • New (23-55)
middleware/keyauth/keyauth.go (2)
middleware/keyauth/extractors.go (4)
  • Extractor (42-48)
  • Source (12-12)
  • SourceAuthHeader (20-20)
  • Chain (211-252)
constants.go (1)
  • HeaderWWWAuthenticate (166-166)
🪛 LanguageTool
docs/middleware/keyauth.md

[grammar] ~263-~263: There might be a mistake here.
Context: ... | nil (panic) | | Extractor | keyauth.Extractor ...

(QB_NEW_EN)

🪛 Gitleaks (8.27.2)
docs/middleware/keyauth.md

216-220: Discovered a potential authorization token provided in a curl command header, which could compromise the curl accessed resource.

(curl-auth-header)

⏰ 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: Compare
  • GitHub Check: repeated
🔇 Additional comments (18)
docs/middleware/encryptcookie.md (1)

98-98: CSRF extractor usage change looks correct

Replacing KeyLookup with Extractor: csrf.FromHeader(csrf.HeaderName) aligns with the v3 extractor pattern and the broader middleware refactor.

middleware/keyauth/config_test.go (1)

30-43: Good coverage of defaulting behavior

Asserts for default Realm and non-nil handlers/extractor cover the happy path when only Validator is provided.

docs/whats_new.md (1)

1115-1117: KeyAuth: Extractor-based configuration note is accurate

Clear summary of breaking changes and the new Extractor/Chain model. Nicely done.

middleware/keyauth/extractors_test.go (3)

83-90: Context acquisition and deferred release pattern looks correct.

The pattern of acquiring the context, deferring its release, and then performing the test is appropriate and follows good resource management practices.


18-27: Well-structured test for missing parameter extraction.

The test correctly validates that FromParam returns ErrMissingAPIKeyInParam when the parameter is missing from the route. The pattern of creating a test route and validating the error within the handler is appropriate.


124-175: Comprehensive chain testing with good edge case coverage.

The test thoroughly covers the chain functionality including:

  • Empty chain returning ErrMissingAPIKey
  • First extractor succeeding
  • Second extractor succeeding when first fails
  • All extractors failing returns the last error
  • Custom extractor returning empty string and nil error

This provides excellent coverage of the chain behavior.

docs/middleware/keyauth.md (3)

17-61: Excellent example demonstrating cookie-based authentication.

The basic example clearly shows how to use the new Extractor API with cookie-based authentication, including proper key validation using constant-time comparison.


224-254: Clear documentation of the new Extractor API and chaining capability.

The documentation effectively explains:

  • The available built-in extractors with clear descriptions
  • How to use the Chain function to combine multiple extractors
  • A practical example showing header and query parameter fallback

This provides excellent guidance for users migrating to the new API.


274-289: Well-structured default configuration with comprehensive error handling.

The default configuration appropriately:

  • Maps all specific missing API key errors to proper status codes
  • Provides clear error messages for each scenario
  • Sets a default realm for WWW-Authenticate headers
  • Uses the common Bearer authentication scheme by default
middleware/keyauth/keyauth.go (4)

15-17: Good use of iota for context key enumeration.

Using iota for the context key is a cleaner approach than hardcoding values, and it follows Go best practices for constant enumeration.


27-29: Appropriate extraction of auth scheme at initialization.

Determining the auth scheme once during middleware initialization is efficient and avoids repeated computation on each request.


38-46: Clean refactor to use the new Extractor API.

The extraction and validation flow is well-structured:

  1. Extract the key using the configured extractor
  2. Validate only if extraction succeeds
  3. Store the key in context and call success handler on valid key

This is a significant improvement over the previous string-based configuration approach.


48-52: Proper WWW-Authenticate header handling.

Setting the WWW-Authenticate header with the auth scheme and realm when authentication fails follows RFC 7235 requirements for HTTP authentication.

middleware/keyauth/keyauth_test.go (5)

24-31: Good extraction of test constants for clarity.

Defining extractor names as constants improves test readability and maintainability.


76-86: Appropriate handling of special characters in test keys.

The test correctly handles encoding issues by using simpler keys for param and cookie extractors where special characters could cause problems in the test setup. This is a pragmatic approach for testing.


192-195: Verify the condition logic for empty test key.

The condition checks testKey which may have been modified from the original test.APIKey. Consider whether you want to check the original API key value or the potentially modified one.

Based on the test logic, when authSource == paramExtractorName and the original test.APIKey is empty, testKey remains empty (lines 76-86 only modify non-empty keys). So checking testKey here appears correct, but adding a comment would improve clarity.

+	// When using param extractor with empty key, the route won't match
 	if authSource == paramExtractorName && testKey == "" {
 		expectedCode = 404
 		expectedBody = "Cannot GET /"
 	}

800-897: Comprehensive WWW-Authenticate header testing.

Excellent test coverage for the WWW-Authenticate header behavior including:

  • Default configuration
  • Custom realm
  • Non-auth-header extractors (no header expected)
  • Success cases (no header expected)
  • Chained extractors with and without auth headers

The parallel test execution and table-driven approach is well-structured.


472-475: Good addition of protected endpoint test.

Adding the /not-allowed endpoint improves test coverage by verifying that the middleware correctly protects routes when the Next function returns false.

Comment on lines 1115 to 1117
The keyauth middleware was updated to introduce a configurable `Realm` field for the `WWW-Authenticate` header.
The old string-based `KeyLookup` configuration has been replaced with an `Extractor` field. Use helper functions like `keyauth.FromHeader`, `keyauth.FromAuthHeader`, or `keyauth.FromCookie` to define where the key should be retrieved from. Multiple sources can be combined with `keyauth.Chain`. See the migration guide below.

Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Ensure WWW-Authenticate behavior is documented for chained extractors

When an auth scheme is present (e.g., FromAuthHeader), the middleware sets the WWW-Authenticate header. If the first extractor in the chain doesn’t specify a scheme, this header may be omitted. Mention that for chains, the scheme is inferred from the first extractor.

To verify code behavior, search for getAuthScheme and confirm it inspects Extractor.AuthScheme and/or walks Extractor.Chain:

Also applies to: 1943-1963


🏁 Script executed:

#!/bin/bash
ast-grep --pattern $'func $_($_$) $_ {\n  $$$\n  getAuthScheme($_)\n  $$$\n}' -A 3
rg -n "getAuthScheme|WWW-Authenticate|HeaderWWWAuthenticate" -A 5

Length of output: 9722


Document WWW-Authenticate behavior for chained extractors

Short summary: I verified getAuthScheme inspects Extractor.AuthScheme and walks Extractor.Chain: it returns the first auth scheme from an extractor using the Authorization header and, if none is found, the middleware does not set the WWW-Authenticate header. Please document this behavior.

Files/locations to update:

  • middleware/keyauth/keyauth.go — getAuthScheme implementation (around lines 67–74) shows it checks e.Source == SourceAuthHeader and iterates e.Chain to find a matching AuthScheme.
  • docs/whats_new.md — update both occurrences (around lines 1115–1117 and 1944–1946) to mention chained extractor behavior.
  • docs/middleware/keyauth.md — add a short note in the Extractor/Realm/default-config section explaining when WWW-Authenticate is set for chains.
  • (optional) middleware/keyauth/keyauth_test.go — referenced tests (e.g., ~lines 682/702) confirm current behavior; update tests or add examples in docs if helpful.

Suggested wording to add:
"Note: When using keyauth.Chain the WWW-Authenticate header is inferred from the first extractor that uses the Authorization header (i.e., the first extractor with SourceAuthHeader). If no extractor in the chain provides an auth scheme, the WWW-Authenticate header will not be set."

Comment on lines +49 to 64
ErrorHandler: func(c fiber.Ctx, err error) error {
switch {
case errors.Is(err, ErrMissingOrMalformedAPIKey),
errors.Is(err, ErrMissingAPIKey),
errors.Is(err, ErrMissingAPIKeyInHeader),
errors.Is(err, ErrMissingAPIKeyInQuery),
errors.Is(err, ErrMissingAPIKeyInParam),
errors.Is(err, ErrMissingAPIKeyInForm),
errors.Is(err, ErrMissingAPIKeyInCookie):
return c.Status(fiber.StatusUnauthorized).SendString(err.Error())
}
return c.Status(fiber.StatusUnauthorized).SendString("Invalid or expired API Key")
},
Realm: "Restricted",
Extractor: FromAuthHeader(fiber.HeaderAuthorization, "Bearer"),
}
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Default ErrorHandler mapping looks good; confirm it aligns with extractor errors

The mapping for missing/malformed errors to 401 with specific messages is appropriate and consistent with the extractor set. After adopting the suggested ErrMissingOrMalformedAPIKey returns in FromAuthHeader, this will produce better client feedback.

To ensure all extractor errors are covered by the default handler, grep for error declarations and references:

Also applies to: 79-91


🏁 Script executed:

#!/bin/bash
rg -n "var \(|ErrMissing.*\)" middleware/keyauth -A 2
rg -n "ErrorHandler.*switch" -n middleware/keyauth/config.go -A 40

Length of output: 7772


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "---- Files with FromAuthHeader ----"
rg -n "FromAuthHeader" middleware/keyauth || true

echo
echo "---- Show middleware/keyauth/extractors.go (first 240 lines) ----"
sed -n '1,240p' middleware/keyauth/extractors.go || true

echo
echo "---- Show middleware/keyauth/config.go (1-160) ----"
sed -n '1,160p' middleware/keyauth/config.go || true

Length of output: 12286


Default ErrorHandler OK — return ErrMissingOrMalformedAPIKey for malformed Authorization header

Confirmed: ConfigDefault.ErrorHandler already covers ErrMissingOrMalformedAPIKey and all ErrMissingAPIKey* variants. However, FromAuthHeader currently returns ErrMissingAPIKeyInHeader for both a missing header and a header with the wrong scheme. I recommend returning ErrMissingOrMalformedAPIKey when the Authorization header is present but malformed so clients receive clearer feedback.

Files to update / check:

  • middleware/keyauth/config.go — ErrorHandler switch already includes ErrMissingOrMalformedAPIKey.
  • middleware/keyauth/extractors.go — FromAuthHeader: change the branch that handles a wrong/mismatched scheme to return ErrMissingOrMalformedAPIKey instead of ErrMissingAPIKeyInHeader.
  • middleware/keyauth/keyauth.go — ErrMissingOrMalformedAPIKey is defined here.
  • Tests to update: middleware/keyauth/extractors_test.go and middleware/keyauth/keyauth_test.go (they assert ErrMissingAPIKeyInHeader in scheme-mismatch cases).
🤖 Prompt for AI Agents
In middleware/keyauth/extractors.go around the branch that handles Authorization
header scheme mismatches, change the returned error from
ErrMissingAPIKeyInHeader to ErrMissingOrMalformedAPIKey so presence of a header
with the wrong scheme is treated as malformed; keep middleware/keyauth/config.go
as-is since ErrorHandler already handles ErrMissingOrMalformedAPIKey; update
tests in middleware/keyauth/extractors_test.go and
middleware/keyauth/keyauth_test.go to expect ErrMissingOrMalformedAPIKey for the
scheme-mismatch cases and adjust any assertions/messages accordingly.

Comment on lines +66 to +78
// configDefault is a helper function to set default values
func configDefault(config ...Config) Config {
// Return default config if nothing provided
if len(config) < 1 {
return ConfigDefault
panic("fiber: keyauth middleware requires a validator function")
}

// Override default config
cfg := config[0]

// Require a validator function
if cfg.Validator == nil {
panic("fiber: keyauth middleware requires a validator function")
}

Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid double-panic paths; handle empty config gracefully then validate

You panic for both “no config provided” and “validator is nil”, with the same message. Handle the no-config case by initializing cfg to zero value, then enforce the validator requirement. This reduces special cases and simplifies reasoning.

-func configDefault(config ...Config) Config {
-	// Return default config if nothing provided
-	if len(config) < 1 {
-		panic("fiber: keyauth middleware requires a validator function")
-	}
-	cfg := config[0]
+func configDefault(config ...Config) Config {
+	// Initialize cfg from provided value or zero value
+	var cfg Config
+	if len(config) > 0 {
+		cfg = config[0]
+	}
 
 	// Require a validator function
 	if cfg.Validator == nil {
 		panic("fiber: keyauth middleware requires a validator function")
 	}

This preserves the panic message for New() without arguments while streamlining the code.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// configDefault is a helper function to set default values
func configDefault(config ...Config) Config {
// Return default config if nothing provided
if len(config) < 1 {
return ConfigDefault
panic("fiber: keyauth middleware requires a validator function")
}
// Override default config
cfg := config[0]
// Require a validator function
if cfg.Validator == nil {
panic("fiber: keyauth middleware requires a validator function")
}
// configDefault is a helper function to set default values
func configDefault(config ...Config) Config {
// Initialize cfg from provided value or zero value
var cfg Config
if len(config) > 0 {
cfg = config[0]
}
// Require a validator function
if cfg.Validator == nil {
panic("fiber: keyauth middleware requires a validator function")
}
🤖 Prompt for AI Agents
In middleware/keyauth/config.go around lines 66 to 78, avoid the double-panic by
treating an absent config as the zero value and then validating the Validator
field; change the flow so if len(config) == 0 you set cfg to Config{} instead of
panicking, and after that check if cfg.Validator == nil and panic with the
existing message if so — this preserves the panic for New() without a validator
while removing the redundant early panic for missing config.

Comment on lines +69 to +79
// Check if the header starts with the specified auth scheme
if authScheme != "" {
schemeLen := len(authScheme)
if len(authHeader) > schemeLen+1 && strings.EqualFold(authHeader[:schemeLen], authScheme) && authHeader[schemeLen] == ' ' {
return strings.TrimSpace(authHeader[schemeLen+1:]), nil
}
return "", ErrMissingAPIKeyInHeader
}

return strings.TrimSpace(authHeader), nil
},
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Authorization parsing can return empty token; treat whitespace-only or malformed values as errors

If the header is "Bearer " (or has extra whitespace), strings.TrimSpace(authHeader[schemeLen+1:]) can yield an empty token while returning nil error. This leads to calling Validator with an empty key. Also, when the scheme doesn't match, returning ErrMissingAPIKeyInHeader hides malformed inputs. Prefer ErrMissingOrMalformedAPIKey and ensure the token is non-empty.

Apply this diff to harden parsing and avoid empty-token success:

-			// Check if the header starts with the specified auth scheme
-			if authScheme != "" {
-				schemeLen := len(authScheme)
-				if len(authHeader) > schemeLen+1 && strings.EqualFold(authHeader[:schemeLen], authScheme) && authHeader[schemeLen] == ' ' {
-					return strings.TrimSpace(authHeader[schemeLen+1:]), nil
-				}
-				return "", ErrMissingAPIKeyInHeader
-			}
-
-			return strings.TrimSpace(authHeader), nil
+			// Check if the header starts with the specified auth scheme
+			if authScheme != "" {
+				schemeLen := len(authScheme)
+				if len(authHeader) < schemeLen+1 || !strings.EqualFold(authHeader[:schemeLen], authScheme) {
+					return "", ErrMissingOrMalformedAPIKey
+				}
+				// Trim any whitespace after the scheme and ensure a non-empty token
+				token := strings.TrimSpace(authHeader[schemeLen:])
+				if token == "" {
+					return "", ErrMissingOrMalformedAPIKey
+				}
+				return token, nil
+			}
+
+			token := strings.TrimSpace(authHeader)
+			if token == "" {
+				return "", ErrMissingAPIKeyInHeader
+			}
+			return token, nil
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Check if the header starts with the specified auth scheme
if authScheme != "" {
schemeLen := len(authScheme)
if len(authHeader) > schemeLen+1 && strings.EqualFold(authHeader[:schemeLen], authScheme) && authHeader[schemeLen] == ' ' {
return strings.TrimSpace(authHeader[schemeLen+1:]), nil
}
return "", ErrMissingAPIKeyInHeader
}
return strings.TrimSpace(authHeader), nil
},
// Check if the header starts with the specified auth scheme
if authScheme != "" {
schemeLen := len(authScheme)
if len(authHeader) < schemeLen+1 || !strings.EqualFold(authHeader[:schemeLen], authScheme) {
return "", ErrMissingOrMalformedAPIKey
}
// Trim any whitespace after the scheme and ensure a non-empty token
token := strings.TrimSpace(authHeader[schemeLen:])
if token == "" {
return "", ErrMissingOrMalformedAPIKey
}
return token, nil
}
token := strings.TrimSpace(authHeader)
if token == "" {
return "", ErrMissingAPIKeyInHeader
}
return token, nil
},
🤖 Prompt for AI Agents
In middleware/keyauth/extractors.go around lines 69 to 79, the current
auth-header parsing can return an empty token (e.g., "Bearer   ") or return
ErrMissingAPIKeyInHeader for malformed inputs; update the logic to TrimSpace the
extracted token and if the result is empty return ErrMissingOrMalformedAPIKey,
and when the scheme check fails return ErrMissingOrMalformedAPIKey instead of
ErrMissingAPIKeyInHeader; also apply the same non-empty trimmed check for the
branch that returns the whole header so no whitespace-only token ever returns
nil error.

@ReneWerner87
Copy link
Member

cli pr gofiber/cli#157

@efectn efectn moved this to Done in v3 Jan 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

4 participants