From b3fae8f6653a7493a37bde1e2e9d2a6b6d6ac48d Mon Sep 17 00:00:00 2001 From: Aidan Gallagher Date: Wed, 14 Jan 2026 16:17:23 +0000 Subject: [PATCH] feat: add custom HTTP header support Add support for custom HTTP headers in API requests via config file. This enables jira-cli to work with Jira instances behind Cloudflare Access or other reverse proxies that require custom authentication headers. Use case: Jira instances protected by Cloudflare Access require a `cf-access-token` header (obtained via `cloudflared access token`) in addition to standard Jira authentication. Without custom header support, requests are blocked at the network layer before reaching Jira. Configuration example: custom_headers: cf-access-token: "" Changes: - Add CustomHeaders field to Config and Client structs - Load custom_headers from config file via viper - Apply custom headers to all HTTP requests --- api/client.go | 5 +++++ pkg/jira/client.go | 48 +++++++++++++++++++++++++++------------------- 2 files changed, 33 insertions(+), 20 deletions(-) diff --git a/api/client.go b/api/client.go index 683f4b16..da9b8cfb 100644 --- a/api/client.go +++ b/api/client.go @@ -61,6 +61,11 @@ func Client(config jira.Config) *jira.Client { config.MTLSConfig.ClientKey = viper.GetString("mtls.client_key") } + // Custom Headers + if config.CustomHeaders == nil { + config.CustomHeaders = viper.GetStringMapString("custom_headers") + } + jiraClient = jira.NewClient( config, jira.WithTimeout(clientTimeout), diff --git a/pkg/jira/client.go b/pkg/jira/client.go index c6435dbc..895f532d 100644 --- a/pkg/jira/client.go +++ b/pkg/jira/client.go @@ -105,25 +105,27 @@ type MTLSConfig struct { // Config is a jira config. type Config struct { - Server string - Login string - APIToken string - AuthType *AuthType - Insecure *bool - Debug bool - MTLSConfig MTLSConfig + Server string + Login string + APIToken string + AuthType *AuthType + Insecure *bool + Debug bool + MTLSConfig MTLSConfig + CustomHeaders map[string]string } // Client is a jira client. type Client struct { - transport http.RoundTripper - insecure bool - server string - login string - authType *AuthType - token string - timeout time.Duration - debug bool + transport http.RoundTripper + insecure bool + server string + login string + authType *AuthType + token string + timeout time.Duration + debug bool + customHeaders map[string]string } // ClientFunc decorates option for client. @@ -132,11 +134,12 @@ type ClientFunc func(*Client) // NewClient instantiates new jira client. func NewClient(c Config, opts ...ClientFunc) *Client { client := Client{ - server: strings.TrimSuffix(c.Server, "/"), - login: c.Login, - token: c.APIToken, - authType: c.AuthType, - debug: c.Debug, + server: strings.TrimSuffix(c.Server, "/"), + login: c.Login, + token: c.APIToken, + authType: c.AuthType, + debug: c.Debug, + customHeaders: c.CustomHeaders, } for _, opt := range opts { @@ -266,6 +269,11 @@ func (c *Client) request(ctx context.Context, method, endpoint string, body []by req.Header.Set(k, v) } + // Apply custom headers from config. + for k, v := range c.customHeaders { + req.Header.Set(k, v) + } + // Set default auth type to `basic`. if c.authType == nil { basic := AuthTypeBasic