package auth import ( "context" "net/http" "strings" ) // ContextKey is a type for context keys to avoid collisions type ContextKey string const ( // ContextKeyUsername is the context key for storing the authenticated username ContextKeyUsername ContextKey = "username" // ContextKeyAuthUser is the context key for storing the raw auth username ContextKeyAuthUser ContextKey = "auth_user" // ContextKeyAuthPass is the context key for storing the raw auth password ContextKeyAuthPass ContextKey = "auth_pass" ) // Credentials holds authentication credentials type Credentials struct { Username string Password string } // GetCredentials extracts authentication credentials from the request // This is the single point where auth mechanism is defined func GetCredentials(r *http.Request) (*Credentials, bool) { username, password, ok := r.BasicAuth() if !ok || username == "" { return nil, false } return &Credentials{ Username: username, Password: password, }, true } // GetUsername extracts and formats the username for display func GetUsername(r *http.Request) string { creds, ok := GetCredentials(r) if !ok { return "Guest" } // Capitalize the username for display return strings.Title(creds.Username) } // GetUsernameFromContext retrieves the username from the request context func GetUsernameFromContext(ctx context.Context) string { if username, ok := ctx.Value(ContextKeyUsername).(string); ok { return username } return "Guest" } // GetCredentialsFromContext retrieves credentials from the request context func GetCredentialsFromContext(ctx context.Context) (*Credentials, bool) { username, okUser := ctx.Value(ContextKeyAuthUser).(string) password, okPass := ctx.Value(ContextKeyAuthPass).(string) if !okUser || !okPass { return nil, false } return &Credentials{ Username: username, Password: password, }, true } // AddAuthToRequest adds authentication credentials to an HTTP request // This should be used when making authenticated requests to internal services func AddAuthToRequest(req *http.Request, creds *Credentials) { if creds != nil { req.SetBasicAuth(creds.Username, creds.Password) } } // NewAuthenticatedRequest creates a new HTTP request with authentication from the source request // This is a convenience method that extracts auth from sourceReq and applies it to the new request func NewAuthenticatedRequest(method, url string, sourceReq *http.Request) (*http.Request, error) { req, err := http.NewRequest(method, url, nil) if err != nil { return nil, err } // Copy authentication from source request if creds, ok := GetCredentials(sourceReq); ok { AddAuthToRequest(req, creds) } return req, nil } // Middleware adds authentication information to the request context // This allows handlers to access auth info without parsing headers repeatedly func Middleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { creds, ok := GetCredentials(r) if ok { ctx := r.Context() ctx = context.WithValue(ctx, ContextKeyUsername, strings.Title(creds.Username)) ctx = context.WithValue(ctx, ContextKeyAuthUser, creds.Username) ctx = context.WithValue(ctx, ContextKeyAuthPass, creds.Password) r = r.WithContext(ctx) } next.ServeHTTP(w, r) }) }