feat: add PROXY_BEARER_TOKEN and PROXY_HEADERS options#13
Conversation
Add support for injecting custom headers into proxied requests: - PROXY_BEARER_TOKEN: shorthand for Authorization: Bearer header - PROXY_HEADERS: comma-separated list of custom headers (format: Header1:Value1,Header2:Value2) Both options are available as environment variables and command-line flags. Header parsing is centralized in main.go for better maintainability.
- Keep header parsing in main.go, move token integration to pkg/mcp-proxy - Update Run function signature to accept headers slice and bearer token - Integrate bearer token with headers map within mcp-proxy package
- Simplify header parsing in main.go by removing validation logic - Change proxy headers from map[string]string to http.Header for proper multi-value support - Move header processing after logger initialization for proper warning messages - Add validation for header format with proper error handling - Add warning when Authorization header is overwritten by bearer token - Use http.Header methods for proper header management
There was a problem hiding this comment.
Pull Request Overview
This PR adds support for custom proxy headers through two new configuration options: PROXY_BEARER_TOKEN for Authorization Bearer headers and PROXY_HEADERS for arbitrary custom headers. The implementation centralizes header parsing in the main function and integrates both types of headers into a unified processing system.
- Add PROXY_BEARER_TOKEN environment variable and CLI flag for Bearer token authentication
- Add PROXY_HEADERS environment variable and CLI flag for custom headers in format "Header1:Value1,Header2:Value2"
- Centralize header parsing and validation logic in main.go for better maintainability
Reviewed Changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| main.go | Adds CLI flags and environment variable parsing for proxy headers and bearer token |
| pkg/mcp-proxy/main.go | Implements header parsing logic and integrates bearer token with custom headers |
| pkg/proxy/main.go | Updates ProxyRouter to accept and apply custom headers to proxied requests |
| README.md | Documents the new PROXY_BEARER_TOKEN and PROXY_HEADERS configuration options |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
| if proxyHeadersMap.Get("Authorization") != "" { | ||
| logger.Warn("Authorization header already set, overwriting with bearer token") | ||
| } | ||
| proxyHeadersMap.Set("Authorization", "Bearer "+proxyBearerToken) |
There was a problem hiding this comment.
The bearer token is being concatenated directly without any validation. Consider validating that the token doesn't already contain 'Bearer ' prefix to prevent malformed Authorization headers like 'Bearer Bearer token123'.
| proxyHeadersMap.Set("Authorization", "Bearer "+proxyBearerToken) | |
| token := proxyBearerToken | |
| if !strings.HasPrefix(strings.ToLower(token), "bearer ") { | |
| token = "Bearer " + token | |
| } | |
| proxyHeadersMap.Set("Authorization", token) |
| if len(parts) != 2 || strings.TrimSpace(parts[0]) == "" || strings.TrimSpace(parts[1]) == "" { | ||
| return fmt.Errorf("invalid proxy header format: %s", header) | ||
| } | ||
| proxyHeadersMap.Add(strings.TrimSpace(parts[0]), strings.TrimSpace(parts[1])) |
There was a problem hiding this comment.
The header validation only checks for empty values after trimming whitespace, but doesn't validate header names against RFC 7230 standards. Invalid header names could cause issues or be exploited. Consider adding validation for valid HTTP header name characters.
| proxyHeadersMap.Add(strings.TrimSpace(parts[0]), strings.TrimSpace(parts[1])) | |
| // RFC 7230: field-name = token; token = 1*tchar; tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA | |
| var validHeaderName = regexp.MustCompile(`^[!#$%&'*+\-.^_` + "`" + `|~0-9A-Za-z]+$`) | |
| for _, header := range proxyHeaders { | |
| parts := strings.SplitN(header, ":", 2) | |
| name := strings.TrimSpace(parts[0]) | |
| value := strings.TrimSpace(parts[1]) | |
| if len(parts) != 2 || name == "" || value == "" { | |
| return fmt.Errorf("invalid proxy header format: %s", header) | |
| } | |
| if !validHeaderName.MatchString(name) { | |
| return fmt.Errorf("invalid proxy header name (must match RFC 7230): %q", name) | |
| } | |
| proxyHeadersMap.Add(name, value) |
Summary