gofr-dev/gofr · error

authorization header already set on request

Error message

authorization header already set on request

What it means

errAuthHeaderPresent is returned by fileTokenDecorator.inject (file_token_auth.go:26) when the outgoing request already carries a non-empty Authorization header. FileTokenAuthConfig is an automatic bearer-token injector; it refuses to silently overwrite a caller-supplied credential, wrapping the sentinel in AuthErr so the caller knows their explicit header collided with injection.

Source

Thrown at pkg/gofr/service/file_token_auth.go:26

	"os"
	"strings"
	"sync"
	"time"

	"gofr.dev/pkg/gofr/logging"
)

const (
	// DefaultTokenFilePath is the standard Kubernetes projected service account token mount path.
	DefaultTokenFilePath = "/var/run/secrets/kubernetes.io/serviceaccount/token" // #nosec G101 -- file path, not a credential

	defaultRefreshInterval = 30 * time.Second
)

var (
	errEmptyTokenFile    = errors.New("token file is empty")
	errTokenUnavailable  = errors.New("no token available")
	errAuthHeaderPresent = errors.New("authorization header already set on request")
)

// FileTokenAuthConfig reads a bearer token from a local file and periodically
// re-reads it to support token rotation (e.g. Kubernetes projected service
// account tokens).
//
// The returned value implements Options, Observable and
// io.Closer. Call Close to stop the background refresh goroutine; it is safe
// to call Close multiple times.
type FileTokenAuthConfig struct {
	tokenFilePath   string
	refreshInterval time.Duration

	logger logging.Logger

	mu    sync.RWMutex
	token string

View on GitHub (pinned to 187eb24962)

Solutions

  1. Remove the Authorization header from your explicit headers map and let FileTokenAuthConfig inject the file-based token.
  2. If you need a custom credential, do not add FileTokenAuthConfig (AddOption) to that HTTP service.
  3. If you intended both, chain two services instead of mixing header auth with file-token auth on one request.
  4. Check for empty-string-only headers: the guard only fires when the existing value is non-empty, so clearing the header fixes it.

Example fix

// before
svc.GetWithHeaders(ctx, "/x", nil, map[string]string{"Authorization": "Bearer manual"})
// after
svc.GetWithHeaders(ctx, "/x", nil, nil) // token injected from file
Defensive patterns

Strategy: validation

Validate before calling

if h, ok := headers["Authorization"]; ok && h != "" {
	delete(headers, "Authorization") // let file-token auth inject
}

Type guard

func hasAuthHeader(headers map[string]string) bool {
	v, ok := headers["Authorization"]
	return ok && v != ""
}

Try / catch

resp, err := svc.GetWithHeaders(ctx, path, qp, headers)
var ae service.AuthErr
if errors.As(err, &ae) && errors.Is(ae.Err, errAuthHeaderPresent) {
	// drop the manual Authorization header and retry once
}

Prevention

When it happens

Trigger: Calling any GetWithHeaders/PostWithHeaders/PutWithHeaders/PatchWithHeaders/DeleteWithHeaders on a service decorated with FileTokenAuthConfig while passing headers containing Authorization with a non-empty value (also exercised directly by TestFileTokenAuthConfig_RejectsExistingAuthHeader).

Common situations: Adding your own "Authorization: Bearer <my-token>" in headers while also enabling file-token auth on the service; middleware that sets auth headers upstream of the decorator; migrating code that previously did manual auth into a decorated service.

Related errors


AI-assisted analysis of gofr-dev/gofr@187eb24962 (2026-09-01). Data as JSON: /api/errors/91ddd18be6e32ac2. Report an issue: GitHub.