diff --git a/cli/packages/util/common.go b/cli/packages/util/common.go
index 5039eb0e6..04c0296ce 100644
--- a/cli/packages/util/common.go
+++ b/cli/packages/util/common.go
@@ -5,6 +5,7 @@ import (
"net/http"
"os"
"strings"
+ "unicode"
"github.com/Infisical/infisical-merge/packages/config"
"github.com/go-resty/resty/v2"
@@ -35,18 +36,67 @@ func GetRestyClientWithCustomHeaders() (*resty.Client, error) {
customHeaders := os.Getenv("INFISICAL_CUSTOM_HEADERS")
if customHeaders != "" {
headers := map[string]string{}
- pairs := strings.Split(customHeaders, " ")
- for _, pair := range pairs {
- kv := strings.SplitN(pair, "=", 2)
- if len(kv) != 2 {
+
+ pos := 0
+ for pos < len(customHeaders) {
+ for pos < len(customHeaders) && unicode.IsSpace(rune(customHeaders[pos])) {
+ pos++
+ }
+
+ if pos >= len(customHeaders) {
+ break
+ }
+
+ keyStart := pos
+ for pos < len(customHeaders) && customHeaders[pos] != '=' && !unicode.IsSpace(rune(customHeaders[pos])) {
+ pos++
+ }
+
+ if pos >= len(customHeaders) || customHeaders[pos] != '=' {
return nil, fmt.Errorf("invalid custom header format. Expected \"headerKey1=value1 headerKey2=value2 ....\" but got %v", customHeaders)
}
- key := strings.TrimSpace(kv[0])
- value := strings.TrimSpace(kv[1])
- if !strings.EqualFold(key, "User-Agent") && !strings.EqualFold(key, "Accept") {
+
+ key := customHeaders[keyStart:pos]
+ pos++
+
+ for pos < len(customHeaders) && unicode.IsSpace(rune(customHeaders[pos])) {
+ pos++
+ }
+
+ var value string
+
+ if pos < len(customHeaders) {
+ if customHeaders[pos] == '"' || customHeaders[pos] == '\'' {
+ quoteChar := customHeaders[pos]
+ pos++
+ valueStart := pos
+
+ for pos < len(customHeaders) &&
+ (customHeaders[pos] != quoteChar ||
+ (pos > 0 && customHeaders[pos-1] == '\\')) {
+ pos++
+ }
+
+ if pos < len(customHeaders) {
+ value = customHeaders[valueStart:pos]
+ pos++
+ } else {
+ value = customHeaders[valueStart:]
+ }
+ } else {
+ valueStart := pos
+ for pos < len(customHeaders) && !unicode.IsSpace(rune(customHeaders[pos])) {
+ pos++
+ }
+ value = customHeaders[valueStart:pos]
+ }
+ }
+
+ if key != "" && !strings.EqualFold(key, "User-Agent") && !strings.EqualFold(key, "Accept") {
headers[key] = value
}
}
+
httpClient.SetHeaders(headers)
}
return httpClient, nil
diff --git a/docs/cli/usage.mdx b/docs/cli/usage.mdx
index d5b7acb4a..a77a648d0 100644
--- a/docs/cli/usage.mdx
+++ b/docs/cli/usage.mdx
@@ -120,6 +120,22 @@ The CLI is designed for a variety of secret management applications ranging from
+
+ ## Custom Request Headers
+
+ The Infisical CLI supports custom HTTP headers for requests to servers protected by authentication services such as Cloudflare Access. Configure these headers using the `INFISICAL_CUSTOM_HEADERS` environment variable:
+
+ ```bash
+ # Syntax: headername1=headervalue1 headername2=headervalue2
+ export INFISICAL_CUSTOM_HEADERS="Access-Client-Id=your-client-id Access-Client-Secret=your-client-secret"
+
+ # Execute Infisical commands after setting the environment variable
+ infisical secrets ls
+ ```
+
+ This functionality enables secure interaction with Infisical instances that require specific authentication headers.
+
+
## History
Your terminal keeps a history with the commands you run. When you create Infisical secrets directly from your terminal, they'll stay there for a while.
diff --git a/docs/sdks/languages/go.mdx b/docs/sdks/languages/go.mdx
index a0bf48687..390ef4310 100644
--- a/docs/sdks/languages/go.mdx
+++ b/docs/sdks/languages/go.mdx
@@ -99,6 +99,10 @@ client := infisical.NewInfisicalClient(context.Background(), infisical.Config{
Defines how long certain responses should be cached in memory, in seconds. When set to a positive value, responses from specific methods (like secret fetching) will be cached for this duration. Set to 0 to disable caching.
+
+
+ Allows you to pass custom headers to the HTTP requests made by the SDK. Expected format is `Header1=Value1 Header2="Value 2"`.
+