fatedier/frp · error

couldn't acquire OIDC token for login: %v

Error message

couldn't acquire OIDC token for login: %v

What it means

Used by frps-side components that obtain their OIDC token from a ValueSource (frp's typed secret-reference mechanism: raw value, environment variable, file, or Kubernetes secret/configmap reference) rather than the client-credentials flow. OidcTokenSourceAuthProvider.generateAccessToken calls valueSource.Resolve(context.Background()); any resolution failure is wrapped with this message and fails Login construction.

Source

Thrown at pkg/auth/oidc.go:236

type OidcTokenSourceAuthProvider struct {
	additionalAuthScopes []v1.AuthScope

	valueSource *v1.ValueSource
}

func NewOidcTokenSourceAuthSetter(additionalAuthScopes []v1.AuthScope, valueSource *v1.ValueSource) *OidcTokenSourceAuthProvider {
	return &OidcTokenSourceAuthProvider{
		additionalAuthScopes: additionalAuthScopes,
		valueSource:          valueSource,
	}
}

func (auth *OidcTokenSourceAuthProvider) generateAccessToken() (accessToken string, err error) {
	ctx := context.Background()
	accessToken, err = auth.valueSource.Resolve(ctx)
	if err != nil {
		return "", fmt.Errorf("couldn't acquire OIDC token for login: %v", err)
	}
	return
}

func (auth *OidcTokenSourceAuthProvider) SetLogin(loginMsg *msg.Login) (err error) {
	loginMsg.PrivilegeKey, err = auth.generateAccessToken()
	return err
}

func (auth *OidcTokenSourceAuthProvider) SetPing(pingMsg *msg.Ping) (err error) {
	if !slices.Contains(auth.additionalAuthScopes, v1.AuthScopeHeartBeats) {
		return nil
	}

	pingMsg.PrivilegeKey, err = auth.generateAccessToken()
	return err
}

View on GitHub (pinned to 6c8a8d0a97)

Solutions

  1. Inspect the wrapped error from Resolve — it identifies which source kind (env/file/secret) failed
  2. Verify the referenced object exists: kubectl get secret <name> -o jsonpath='{.data.<key>}' or check the env var with printenv
  3. Create or mount the secret/file before starting the process, and ensure the service account can read it
  4. If the token is static for testing, use a plain value source first, then switch to the secret reference

Example fix

# before (secret not yet created)
valueSource:
  secretKeyRef:
    name: frp-oidc-token
    key: token

# after: create it first
# kubectl create secret generic frp-oidc-token --from-literal=token=<jwt>
valueSource:
  secretKeyRef:
    name: frp-oidc-token
    key: token
Defensive patterns

Strategy: validation

Validate before calling

switch {
case vs.SecretKeyRef != nil:
    _, err := k8sClient.CoreV1().Secrets(ns).Get(ctx, vs.SecretKeyRef.Name, metav1.GetOptions{})
    if err != nil { return fmt.Errorf("secret %s missing: %w", vs.SecretKeyRef.Name, err) }
case vs.Env != nil:
    if os.Getenv(vs.Env) == "" { return fmt.Errorf("env %s unset", vs.Env) }
case vs.File != nil:
    if _, err := os.Stat(vs.File); err != nil { return err }
}

Prevention

When it happens

Trigger: Configuring an OidcTokenSourceAuthProvider whose ValueSource points to a missing environment variable, a nonexistent file path, or a Kubernetes secret that does not exist / is not mounted / has no such key; Resolve also fails on malformed reference syntax.

Common situations: Kubernetes deployments where the secret holding the OIDC token was not created before frps started; the referenced env var is only set in a different container; file-based token path not mounted; typo in the secret name or key.

Related errors


AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15). Data as JSON: /api/errors/af716d72b32333c4. Report an issue: GitHub.