netbirdio/netbird · error

interactive sso login failed: %v

Error message

interactive sso login failed: %v

What it means

Wraps foregroundGetTokenInfo, the interactive OAuth device-authorization flow run directly by the CLI (not via the daemon): requesting device auth info from management and waiting for the token. It fails when the flow cannot start (see 237: management/IdP side rejects the device-authorize request) or when waiting for the token fails (see 238: code expired, denied, poll error), or when constructing the OAuth flow itself fails.

Source

Thrown at client/cmd/login.go:388

}

func foregroundLogin(ctx context.Context, cmd *cobra.Command, config *profilemanager.Config, setupKey string, profileID profilemanager.ID) error {
	authClient, err := auth.NewAuth(ctx, config.PrivateKey, config.ManagementURL, config)
	if err != nil {
		return fmt.Errorf("failed to create auth client: %v", err)
	}
	defer authClient.Close()

	needsLogin, err := authClient.IsLoginRequired(ctx)
	if err != nil {
		return fmt.Errorf("check login required: %v", err)
	}

	jwtToken := ""
	if setupKey == "" && needsLogin {
		tokenInfo, err := foregroundGetTokenInfo(ctx, cmd, config, profileID)
		if err != nil {
			return fmt.Errorf("interactive sso login failed: %v", err)
		}
		jwtToken = tokenInfo.GetTokenToUse()
	}

	err, _ = authClient.Login(ctx, setupKey, jwtToken)
	if err != nil {
		return fmt.Errorf("login failed: %v", err)
	}

	return nil
}

func foregroundGetTokenInfo(ctx context.Context, cmd *cobra.Command, config *profilemanager.Config, profileID profilemanager.ID) (*auth.TokenInfo, error) {
	hint := ""
	pm := profilemanager.NewProfileManager()
	profileState, err := pm.GetProfileState(profileID)
	if err != nil {
		log.Debugf("failed to get profile state for login hint: %v", err)

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Confirm management actually has an IdP configured for SSO; otherwise log in with a setup key ('netbird up --setup-key <key>')
  2. Rerun the flow and complete the browser approval before the user code expires
  3. Check management and IdP logs for the rejected device-authorization request
  4. Verify system clock sync (timedatectl / w32tm) on both client and servers
Defensive patterns

Strategy: try-catch

Validate before calling

// If the account has no SSO, steer to setup-key login before attempting the flow
if setupKey == "" && !accountHasIdP {
    return fmt.Errorf("no IdP configured; use --setup-key or 'netbird up --setup-key'")
}

Try / catch

tokenInfo, err := foregroundGetTokenInfo(ctx, cmd, config, profileID)
if err != nil {
    if strings.Contains(err.Error(), "device-authorize") || strings.Contains(err.Error(), "flow info") {
        // start failure: IdP/management side; do not blind-retry
        return fmt.Errorf("interactive sso login failed (check IdP config): %w", err)
    }
    // wait failure: often expiry; a single retry after re-displaying the code is reasonable
    return fmt.Errorf("interactive sso login failed: %w", err)
}

Prevention

When it happens

Trigger: Management has no IdP/SSO configured so device authorization is unavailable; user never completes or denies the browser consent; device code expires; network interruption during the token poll; clock skew between client and IdP affecting code validity.

Common situations: Self-hosted management where OIDC/IdP setup was skipped, but the client attempted interactive login instead of using a setup key; Slow or abandoned browser logins in headless-ish workflows; IdP outage or misconfigured client ID/issuer on management

Related errors


AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16). Data as JSON: /api/errors/aa971a88afcac11e. Report an issue: GitHub.