55// which requires Authorization headers to contain the API key directly
66// without any scheme prefix (e.g., NOT "Bearer <key>").
77//
8- // Example usage:
8+ // The package provides both full parsing with error handling (ParseAuthHeader)
9+ // and convenience methods for specific use cases (ExtractAgentID, ValidateAPIKey).
910//
11+ // Usage Guidelines:
12+ //
13+ // - Use ParseAuthHeader() for complete authentication with error handling:
14+ // Returns both API key and agent ID, with errors for missing/invalid headers.
15+ //
16+ // - Use ExtractAgentID() when you only need the agent ID and want automatic
17+ // fallback to "default" instead of error handling.
18+ //
19+ // - Use ValidateAPIKey() to check if a provided key matches the expected value.
20+ // Automatically handles the case where authentication is disabled (no expected key).
21+ //
22+ // Example:
23+ //
24+ // // Full authentication
1025// apiKey, agentID, err := auth.ParseAuthHeader(r.Header.Get("Authorization"))
1126// if err != nil {
12- // // Handle error
27+ // return err
1328// }
29+ // if !auth.ValidateAPIKey(apiKey, expectedKey) {
30+ // return errors.New("invalid API key")
31+ // }
32+ //
33+ // // Extract agent ID only (for context, not authentication)
34+ // agentID := auth.ExtractAgentID(r.Header.Get("Authorization"))
1435package auth
1536
1637import (
1738 "errors"
1839 "strings"
1940
2041 "github.com/githubnext/gh-aw-mcpg/internal/logger"
42+ "github.com/githubnext/gh-aw-mcpg/internal/logger/sanitize"
2143)
2244
2345var log = logger .New ("auth:header" )
2951 ErrInvalidAuthHeader = errors .New ("invalid Authorization header format" )
3052)
3153
32- // sanitizeForLogging returns a sanitized version of the input string for safe logging.
33- // It shows only the first 4 characters followed by "..." to prevent exposing sensitive data.
34- // For strings with 4 or fewer characters, it returns only "...".
35- func sanitizeForLogging (input string ) string {
36- if len (input ) > 4 {
37- return input [:4 ] + "..."
38- } else if len (input ) > 0 {
39- return "..."
40- }
41- return ""
42- }
43-
4454// ParseAuthHeader parses the Authorization header and extracts the API key and agent ID.
4555// Per MCP spec 7.1, the Authorization header should contain the API key directly
4656// without any Bearer prefix or other scheme.
@@ -54,7 +64,7 @@ func sanitizeForLogging(input string) string {
5464// - agentID: The extracted agent/session identifier
5565// - error: ErrMissingAuthHeader if header is empty, nil otherwise
5666func ParseAuthHeader (authHeader string ) (apiKey string , agentID string , error error ) {
57- log .Printf ("Parsing auth header: sanitized=%s, length=%d" , sanitizeForLogging (authHeader ), len (authHeader ))
67+ log .Printf ("Parsing auth header: sanitized=%s, length=%d" , sanitize . TruncateSecret (authHeader ), len (authHeader ))
5868
5969 if authHeader == "" {
6070 log .Print ("Auth header missing, returning error" )
@@ -96,3 +106,23 @@ func ValidateAPIKey(provided, expected string) bool {
96106 log .Printf ("API key validation result: matches=%t" , matches )
97107 return matches
98108}
109+
110+ // ExtractAgentID extracts the agent ID from an Authorization header.
111+ // This is a convenience wrapper around ParseAuthHeader that only returns the agent ID.
112+ // Returns "default" if the header is empty or cannot be parsed.
113+ //
114+ // This function is intended for use cases where you only need the agent ID
115+ // and don't need full error handling. For complete authentication handling,
116+ // use ParseAuthHeader instead.
117+ func ExtractAgentID (authHeader string ) string {
118+ if authHeader == "" {
119+ return "default"
120+ }
121+
122+ _ , agentID , err := ParseAuthHeader (authHeader )
123+ if err != nil {
124+ return "default"
125+ }
126+
127+ return agentID
128+ }
0 commit comments