Part of duplicate code analysis: #1810
Summary
authMiddleware in internal/server/auth.go and extractAndValidateSession in internal/server/http_helpers.go both independently extract the Authorization header and produce their own error log + HTTP error response when it is absent. The two functions serve slightly different purposes (API key validation vs. session ID extraction) but share an identical header-reading preamble with nearly identical error handling.
Duplication Details
Pattern: Authorization header extraction + missing-header error path
-
Severity: Low
-
Occurrences: 2
-
Locations:
internal/server/auth.go lines 44–53 (authMiddleware)
internal/server/http_helpers.go lines 44–52 (extractAndValidateSession)
-
Code Sample:
// authMiddleware (auth.go lines 44–53)
authHeader := r.Header.Get("Authorization")
if authHeader == "" {
logAuth.Printf("Authentication failed: missing Authorization header")
logger.LogErrorMd("auth", "Authentication failed: missing Authorization header, remote=%s, path=%s", r.RemoteAddr, r.URL.Path)
logRuntimeError("authentication_failed", "missing_auth_header", r, nil)
http.Error(w, "Unauthorized: missing Authorization header", http.StatusUnauthorized)
return
}
// extractAndValidateSession (http_helpers.go lines 44–52)
authHeader := r.Header.Get("Authorization")
sessionID := auth.ExtractSessionID(authHeader)
if sessionID == "" {
logHelpers.Printf("Session extraction failed: no Authorization header, remote=%s", r.RemoteAddr)
logger.LogError("client", "Rejected MCP client connection: no Authorization header, remote=%s, path=%s", r.RemoteAddr, r.URL.Path)
log.Printf("[%s] %s %s - REJECTED: No Authorization header", r.RemoteAddr, r.Method, r.URL.Path)
return ""
}
Impact Analysis
- Maintainability: Header name (
"Authorization"), log category names, and error strings are repeated across two files. A rename or message change must be applied in both.
- Bug Risk: Low — both paths are exercised by their respective tests, but a subtle difference (e.g., one logs to
LogErrorMd and the other to LogError) could cause inconsistent audit trails.
- Code Bloat: ~10 lines of near-identical logic.
Refactoring Recommendations
-
Extract a shared getAuthHeader helper in internal/server/auth.go or internal/auth:
// getAuthHeader retrieves and validates the presence of the Authorization header.
// Returns the header value and true on success, or writes a 401 response and returns false.
func getAuthHeader(w http.ResponseWriter, r *http.Request) (string, bool) {
h := r.Header.Get("Authorization")
if h == "" {
logger.LogError("auth", "Missing Authorization header, remote=%s, path=%s", r.RemoteAddr, r.URL.Path)
http.Error(w, "Unauthorized: missing Authorization header", http.StatusUnauthorized)
return "", false
}
return h, true
}
Both authMiddleware and extractAndValidateSession can call this helper, then diverge on their specific validation logic.
-
Alternatively, since authMiddleware already runs before extractAndValidateSession in the middleware chain, extractAndValidateSession can rely on the header being present (validated upstream) and remove its own missing-header check, simplifying the flow.
Implementation Checklist
Parent Issue
See parent analysis report: #1810
Related to #1810
Generated by Duplicate Code Detector · ◷
Part of duplicate code analysis: #1810
Summary
authMiddlewareininternal/server/auth.goandextractAndValidateSessionininternal/server/http_helpers.goboth independently extract theAuthorizationheader and produce their own error log + HTTP error response when it is absent. The two functions serve slightly different purposes (API key validation vs. session ID extraction) but share an identical header-reading preamble with nearly identical error handling.Duplication Details
Pattern: Authorization header extraction + missing-header error path
Severity: Low
Occurrences: 2
Locations:
internal/server/auth.golines 44–53 (authMiddleware)internal/server/http_helpers.golines 44–52 (extractAndValidateSession)Code Sample:
Impact Analysis
"Authorization"), log category names, and error strings are repeated across two files. A rename or message change must be applied in both.LogErrorMdand the other toLogError) could cause inconsistent audit trails.Refactoring Recommendations
Extract a shared
getAuthHeaderhelper ininternal/server/auth.goorinternal/auth:Both
authMiddlewareandextractAndValidateSessioncan call this helper, then diverge on their specific validation logic.Alternatively, since
authMiddlewarealready runs beforeextractAndValidateSessionin the middleware chain,extractAndValidateSessioncan rely on the header being present (validated upstream) and remove its own missing-header check, simplifying the flow.Implementation Checklist
internal/server/auth.goand/orinternal/server/http_helpers.gointernal/server/auth_test.goandinternal/server/http_helpers_test.gomake test-unitto confirm no regressionParent Issue
See parent analysis report: #1810
Related to #1810