package cognitoauth import ( "fmt" "log/slog" "os" "strings" ) // ValidatePermitIOConfiguration validates PDP connectivity and API key at startup // This function should be called during application startup to ensure configuration is correct // before processing any real authorization requests. // // It makes a dummy permission check to verify the API key is valid and PDP is reachable. // // If DISABLE_AUTH=true, validation is skipped and function returns success. // Returns an error if the check fails, which should cause the application to halt startup. func ValidatePermitIOConfiguration() error { // Skip validation if auth is disabled disableAuth := os.Getenv("DISABLE_AUTH") if strings.ToLower(disableAuth) == "true" { fmt.Println("✓ Permit.io validation skipped (DISABLE_AUTH=true)") return nil } pdpURL := strings.TrimSpace(os.Getenv("PERMIT_IO_PDP_URL")) apiKey := strings.TrimSpace(os.Getenv("PERMIT_IO_API_KEY")) // Apply default for PDP URL if not set or whitespace-only if pdpURL == "" { pdpURL = "http://localhost:7766" } if apiKey == "" { return fmt.Errorf("PERMIT_IO_API_KEY environment variable must be set") } // Test API key validity and PDP connectivity with a dummy permission check logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelWarn})) permitClient := NewPermitIOClient(apiKey, pdpURL, logger) // Use dummy test data that will likely be denied but should work with valid API key testUser := "startup-validation-user-12345" testAction := "read" testResource := "startup-validation-resource" _, err := permitClient.CheckPermission(testUser, testAction, testResource) if err != nil { // Check for specific error patterns to distinguish error types errStr := err.Error() if strings.Contains(errStr, "UnexpectedError") && (strings.Contains(errStr, "connection refused") || strings.Contains(errStr, "no such host")) { return fmt.Errorf("Permit.io PDP connectivity failed with PDP_URL=%s: %v", pdpURL, err) } if strings.Contains(errStr, "Unauthorized") || strings.Contains(errStr, "Invalid PDP token") || strings.Contains(errStr, "api_error") { return fmt.Errorf("Permit.io API key validation failed with API_KEY=%s and PDP_URL=%s: %v", maskAPIKey(apiKey), pdpURL, err) } if strings.Contains(errStr, "UnprocessableEntityError") { return fmt.Errorf("Permit.io API configuration error with API_KEY=%s and PDP_URL=%s: %v", maskAPIKey(apiKey), pdpURL, err) } // Any other error is also a configuration problem return fmt.Errorf("Permit.io validation failed with API_KEY=%s and PDP_URL=%s: %v", maskAPIKey(apiKey), pdpURL, err) } // Success - both PDP connectivity and API key are valid fmt.Printf("✓ Permit.io configuration validated successfully (PDP_URL=%s, API_KEY=%s)\n", pdpURL, maskAPIKey(apiKey)) return nil } // maskAPIKey masks the API key for logging, showing only the first 8 characters func maskAPIKey(apiKey string) string { if len(apiKey) <= 8 { return "***masked***" } return apiKey[:8] + "..." }