From 9592fb9063781cfb381eb4204a279fa7444e4b29 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 29 Apr 2026 22:25:01 +0000 Subject: [PATCH 1/3] fix: auto-authenticate with Universal Auth client credentials in GetInfisicalToken MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When INFISICAL_UNIVERSAL_AUTH_CLIENT_ID and INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET environment variables are set, GetInfisicalToken() now automatically exchanges them for an access token using the existing UniversalAuthLogin() function. Previously, GetInfisicalToken() only checked for pre-existing access tokens (--token flag, INFISICAL_UNIVERSAL_AUTH_ACCESS_TOKEN, INFISICAL_TOKEN env vars). If none were found, it returned nil, causing commands like 'infisical run' to fall back to the interactive login flow — which fails in non-interactive environments like Claude Code, CI runners, and other automated tooling. This fixes 'run', 'export', 'secrets', and all other commands that use GetInfisicalToken. Co-Authored-By: jake --- packages/util/helper.go | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/packages/util/helper.go b/packages/util/helper.go index cdaef77c..0e423fc6 100644 --- a/packages/util/helper.go +++ b/packages/util/helper.go @@ -303,7 +303,28 @@ func GetInfisicalToken(cmd *cobra.Command) (token *models.TokenDetails, err erro } } - if infisicalToken == "" { // If it's empty, we return nothing at all. + if infisicalToken == "" { + // Check if Universal Auth client credentials are available for automatic authentication. + // This allows commands like `infisical run` to work when INFISICAL_UNIVERSAL_AUTH_CLIENT_ID + // and INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET are set, without requiring a prior `infisical login`. + clientId := os.Getenv(INFISICAL_UNIVERSAL_AUTH_CLIENT_ID_NAME) + clientSecret := os.Getenv(INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET_NAME) + + if clientId != "" && clientSecret != "" { + log.Debug().Msg("No explicit token found, attempting automatic authentication via Universal Auth client credentials") + loginResponse, err := UniversalAuthLogin(clientId, clientSecret) + if err != nil { + return nil, fmt.Errorf("failed to authenticate with Universal Auth using %s and %s environment variables: %w", + INFISICAL_UNIVERSAL_AUTH_CLIENT_ID_NAME, INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET_NAME, err) + } + + return &models.TokenDetails{ + Type: UNIVERSAL_AUTH_TOKEN_IDENTIFIER, + Token: loginResponse.AccessToken, + Source: fmt.Sprintf("%s and %s environment variables", INFISICAL_UNIVERSAL_AUTH_CLIENT_ID_NAME, INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET_NAME), + }, nil + } + return nil, nil } From 4a991c203e075f24f7d7f6300252dfa599547135 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 29 Apr 2026 23:45:23 +0000 Subject: [PATCH 2/3] fix: address Codex review feedback on Universal Auth auto-login MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Split GetInfisicalToken into local-only DetectInfisicalToken (for PersistentPreRun warning) and network-capable GetInfisicalToken, so the root command no longer performs a network call or double-mints tokens on every CLI invocation. - Skip auto-UA-login when --auth-method flag or INFISICAL_AUTH_METHOD env var is set, so gateway/relay flows using AWS/GCP/K8s auth are not short-circuited by stale UA credentials in the environment. - Reduce UniversalAuthLogin retry count from 10000 (≈55h worst-case) to 3 retries with 2-5s wait, so CLI commands fail fast on transport errors instead of blocking indefinitely. Co-Authored-By: jake --- packages/cmd/root.go | 2 +- packages/util/helper.go | 130 +++++++++++++++++++++++++++------------- 2 files changed, 90 insertions(+), 42 deletions(-) diff --git a/packages/cmd/root.go b/packages/cmd/root.go index 1a8bfa62..9cece465 100644 --- a/packages/cmd/root.go +++ b/packages/cmd/root.go @@ -112,7 +112,7 @@ func init() { loggedInDetails, err := util.GetCurrentLoggedInUserDetails(false) if !silent && err == nil && loggedInDetails.IsUserLoggedIn && !loggedInDetails.LoginExpired { - token, err := util.GetInfisicalToken(cmd) + token, err := util.DetectInfisicalToken(cmd) if err == nil && token != nil { util.PrintWarningWithWriter(fmt.Sprintf("Your logged-in session is being overwritten by the token provided from the %s.", token.Source), cmd.ErrOrStderr()) diff --git a/packages/util/helper.go b/packages/util/helper.go index 0e423fc6..79d130a7 100644 --- a/packages/util/helper.go +++ b/packages/util/helper.go @@ -279,80 +279,128 @@ func IsSecretTypeValid(s string) bool { return false } -func GetInfisicalToken(cmd *cobra.Command) (token *models.TokenDetails, err error) { - infisicalToken, err := cmd.Flags().GetString("token") +// DetectInfisicalToken checks for locally-available tokens and credentials +// without performing any network calls. Use this when you only need to know +// whether a token source is present (e.g. for the "session overwritten" warning +// in PersistentPreRun). +func DetectInfisicalToken(cmd *cobra.Command) (token *models.TokenDetails, err error) { + infisicalToken, source := lookupLocalToken(cmd) + if infisicalToken != "" { + return classifyToken(infisicalToken, source), nil + } + + clientId := os.Getenv(INFISICAL_UNIVERSAL_AUTH_CLIENT_ID_NAME) + clientSecret := os.Getenv(INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET_NAME) + if clientId != "" && clientSecret != "" { + return &models.TokenDetails{ + Type: UNIVERSAL_AUTH_TOKEN_IDENTIFIER, + Source: fmt.Sprintf("%s and %s environment variables", INFISICAL_UNIVERSAL_AUTH_CLIENT_ID_NAME, INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET_NAME), + }, nil + } - if err != nil { - return nil, err + return nil, nil +} + +func GetInfisicalToken(cmd *cobra.Command) (token *models.TokenDetails, err error) { + infisicalToken, source := lookupLocalToken(cmd) + if infisicalToken != "" { + return classifyToken(infisicalToken, source), nil } - var source = "--token flag" + // Skip auto-login when an explicit auth method is requested via + // --auth-method flag or INFISICAL_AUTH_METHOD env var, so that + // other auth flows (AWS, GCP, K8s, etc.) are not short-circuited. + if isAuthMethodSpecified(cmd) { + return nil, nil + } - if infisicalToken == "" { // If no flag is passed, we first check for the universal auth access token env variable. - infisicalToken = os.Getenv(INFISICAL_UNIVERSAL_AUTH_ACCESS_TOKEN_NAME) - source = fmt.Sprintf("%s environment variable", INFISICAL_UNIVERSAL_AUTH_ACCESS_TOKEN_NAME) + clientId := os.Getenv(INFISICAL_UNIVERSAL_AUTH_CLIENT_ID_NAME) + clientSecret := os.Getenv(INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET_NAME) - if infisicalToken == "" { // If it's still empty after the first env check, we check for the service token env variable. - infisicalToken = os.Getenv(INFISICAL_TOKEN_NAME) - source = fmt.Sprintf("%s environment variable", INFISICAL_TOKEN_NAME) + if clientId != "" && clientSecret != "" { + log.Debug().Msg("No explicit token found, attempting automatic authentication via Universal Auth client credentials") + loginResponse, err := UniversalAuthLogin(clientId, clientSecret) + if err != nil { + return nil, fmt.Errorf("failed to authenticate with Universal Auth using %s and %s environment variables: %w", + INFISICAL_UNIVERSAL_AUTH_CLIENT_ID_NAME, INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET_NAME, err) } - if infisicalToken == "" { // if its still empty, check for the `TOKEN` environment variable (for gateway helm) - infisicalToken = os.Getenv(INFISICAL_GATEWAY_TOKEN_NAME_LEGACY) - source = fmt.Sprintf("%s environment variable", INFISICAL_GATEWAY_TOKEN_NAME_LEGACY) - } + return &models.TokenDetails{ + Type: UNIVERSAL_AUTH_TOKEN_IDENTIFIER, + Token: loginResponse.AccessToken, + Source: fmt.Sprintf("%s and %s environment variables", INFISICAL_UNIVERSAL_AUTH_CLIENT_ID_NAME, INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET_NAME), + }, nil } - if infisicalToken == "" { - // Check if Universal Auth client credentials are available for automatic authentication. - // This allows commands like `infisical run` to work when INFISICAL_UNIVERSAL_AUTH_CLIENT_ID - // and INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET are set, without requiring a prior `infisical login`. - clientId := os.Getenv(INFISICAL_UNIVERSAL_AUTH_CLIENT_ID_NAME) - clientSecret := os.Getenv(INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET_NAME) + return nil, nil +} - if clientId != "" && clientSecret != "" { - log.Debug().Msg("No explicit token found, attempting automatic authentication via Universal Auth client credentials") - loginResponse, err := UniversalAuthLogin(clientId, clientSecret) - if err != nil { - return nil, fmt.Errorf("failed to authenticate with Universal Auth using %s and %s environment variables: %w", - INFISICAL_UNIVERSAL_AUTH_CLIENT_ID_NAME, INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET_NAME, err) - } +// lookupLocalToken checks for an explicit token from flags and env vars. +// No network calls are made. +func lookupLocalToken(cmd *cobra.Command) (token string, source string) { + infisicalToken, err := cmd.Flags().GetString("token") + if err != nil { + return "", "" + } - return &models.TokenDetails{ - Type: UNIVERSAL_AUTH_TOKEN_IDENTIFIER, - Token: loginResponse.AccessToken, - Source: fmt.Sprintf("%s and %s environment variables", INFISICAL_UNIVERSAL_AUTH_CLIENT_ID_NAME, INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET_NAME), - }, nil - } + if infisicalToken != "" { + return infisicalToken, "--token flag" + } - return nil, nil + if v := os.Getenv(INFISICAL_UNIVERSAL_AUTH_ACCESS_TOKEN_NAME); v != "" { + return v, fmt.Sprintf("%s environment variable", INFISICAL_UNIVERSAL_AUTH_ACCESS_TOKEN_NAME) + } + + if v := os.Getenv(INFISICAL_TOKEN_NAME); v != "" { + return v, fmt.Sprintf("%s environment variable", INFISICAL_TOKEN_NAME) } + if v := os.Getenv(INFISICAL_GATEWAY_TOKEN_NAME_LEGACY); v != "" { + return v, fmt.Sprintf("%s environment variable", INFISICAL_GATEWAY_TOKEN_NAME_LEGACY) + } + + return "", "" +} + +func classifyToken(infisicalToken, source string) *models.TokenDetails { if strings.HasPrefix(infisicalToken, "st.") { return &models.TokenDetails{ Type: SERVICE_TOKEN_IDENTIFIER, Token: infisicalToken, Source: source, - }, nil + } } - return &models.TokenDetails{ Type: UNIVERSAL_AUTH_TOKEN_IDENTIFIER, Token: infisicalToken, Source: source, - }, nil + } +} +// isAuthMethodSpecified returns true when the caller has explicitly requested +// a machine-identity auth strategy, either via the --auth-method CLI flag or +// the INFISICAL_AUTH_METHOD environment variable. +func isAuthMethodSpecified(cmd *cobra.Command) bool { + if f := cmd.Flags().Lookup("auth-method"); f != nil && f.Changed { + return true + } + if os.Getenv(INFISICAL_AUTH_METHOD_NAME) != "" { + return true + } + return false } +const universalAuthAutoLoginRetries = 3 + func UniversalAuthLogin(clientId string, clientSecret string) (api.UniversalAuthLoginResponse, error) { httpClient, err := GetRestyClientWithCustomHeaders() if err != nil { return api.UniversalAuthLoginResponse{}, err } - httpClient.SetRetryCount(10000). - SetRetryMaxWaitTime(20 * time.Second). - SetRetryWaitTime(5 * time.Second) + httpClient.SetRetryCount(universalAuthAutoLoginRetries). + SetRetryMaxWaitTime(5 * time.Second). + SetRetryWaitTime(2 * time.Second) tokenResponse, err := api.CallUniversalAuthLogin(httpClient, api.UniversalAuthLoginRequest{ClientId: clientId, ClientSecret: clientSecret}) if err != nil { From b1fae84fc1564e96d03a38b37f301a5c28cad82d Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Thu, 30 Apr 2026 01:10:00 +0000 Subject: [PATCH 3/3] fix: restrict auth-method bypass to commands that define the flag Only check INFISICAL_AUTH_METHOD env var when the command actually has the --auth-method flag registered (e.g. gateway, relay). Commands like run, export, and secrets do not define this flag, so a globally-set INFISICAL_AUTH_METHOD should not prevent auto-login for those commands. Co-Authored-By: jake --- packages/util/helper.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/util/helper.go b/packages/util/helper.go index 79d130a7..9c29f625 100644 --- a/packages/util/helper.go +++ b/packages/util/helper.go @@ -379,9 +379,16 @@ func classifyToken(infisicalToken, source string) *models.TokenDetails { // isAuthMethodSpecified returns true when the caller has explicitly requested // a machine-identity auth strategy, either via the --auth-method CLI flag or -// the INFISICAL_AUTH_METHOD environment variable. +// the INFISICAL_AUTH_METHOD environment variable. The env var is only checked +// when the command actually defines the --auth-method flag (e.g. gateway, relay), +// so that commands like run/export/secrets are not affected by a globally-set +// INFISICAL_AUTH_METHOD. func isAuthMethodSpecified(cmd *cobra.Command) bool { - if f := cmd.Flags().Lookup("auth-method"); f != nil && f.Changed { + f := cmd.Flags().Lookup("auth-method") + if f == nil { + return false + } + if f.Changed { return true } if os.Getenv(INFISICAL_AUTH_METHOD_NAME) != "" {