The problem with both your attempts is that neither was expanded to generate an actual :12. This means that TikZ sees the control sequence \c_colon_str instead of its expansion, :12.
To have this working you need to expand \c_colon_str (I'm ignoring the \char_generate:nn approach because it would generate the same thing, with more effort) before \tikzset does it's thing. In general there are two ways to do what you want, but as you say in the comments, both are quite verbose.
The first is the good ol' \edef\x{<stuff-to-expand>}\x. This is provided by expl3 under the name \use:x, which does as the name suggests: it does an x-expansion (\edef) in the argument, then uses it. There are two main issues with this approach: 1) everything is expanded, and 2) parameter tokens (#) need to be doubled. In your case the label would change from (simplified for brevity):
\tikzset{label={[ #2,blue] #1\c_colon_str \c_iskustvo_highlight_font_tl #3}}
to
\use:x{\exp_not:N\tikzset{label={[##2,blue]##1\c_colon_str\exp_not:N\c_iskustvo_highlight_font_tl##3}}}
Note the added \exp_not:N before every control sequence (and every active character should also be \exp_not:N'ed), and the doubled #. You could avoid doubling hashes by either wrapping everything else in \exp_not:n (not N):
\use:x{\exp_not:N\tikzset{label={\exp_not:n{[#2,blue]#1}\c_colon_str\exp_not:n{\c_iskustvo_highlight_font_tl#3}}}}
which is not exactly shorter. To avoid doubling the hashes you can use the e-type expansion instead of x, but there's not much else to gain from it. The e-type is the e-TeX primitive \expanded (introduced in pdfTeX and XeTeX in TeXLive 2019 and LuaTeX much earlier) or, in older distribution, an emulation of it written in expl3 (which makes it much slower).
The other approach is to define a macro which takes as argument the token you want to replace. The basic idea is to do \def\__temp:w#1{<stuff with #1>} and \exp_args:No\__temp:w{\c_colon_str}, then the expansion of \c_colon_str will be inserted in the proper places. In your case, the label would change from (spaces added for clarity):
\tikzset { label = {[##2, blue]##1 \c_colon_str \c_iskustvo_highlight_font_tl ##3} }
to:
\cs_set_protected:Npn \__iskustvo_tmp:w #1
{ \tikzset { label = {[##2, blue]##1 #1 \c_iskustvo_highlight_font_tl ##3} } }
\exp_args:NV \__iskustvo_tmp:w \c_colon_str
The advantage of this method is that you'll hardly run into expansion problems. The downside is that there is a whole lot of boilerplate code to define the temporary macro and use it, plus all hashes must be doubled. It's basically a matter of choice now.
However TikZ is not designed work under unusual catcode regimes (such as expl3's), so I recommend you leave TikZ code separate from expl3 code to avoid this kind of problem. Indeed, interfacing LaTeX3 code with LaTeX2e code is a recurrent problem, mainly due to the different catcode settings. One way to do that is to replace _ by @ in a variable name, so that \c_iskustvo_highlight_font_tl becomes \c@iskustvo@highlight@font@tl. In fact this is done in expl3.sty to keep track of load-time options before loading the LaTeX3 kernel itself. My suggestion for your code:
\documentclass{article}
\RequirePackage[utf8]{inputenc}
\RequirePackage{tikz}
\RequirePackage{xparse}
\usetikzlibrary{fit}
\usetikzlibrary{shapes}
\makeatletter
\ExplSyntaxOn
\tl_const:Nn \c@iskustvo@highlight@font@tl {\fontsize {20} {24} \selectfont \bfseries}
\ExplSyntaxOff
% #1 Angle
% #2 Relative position
% #3 Text
\tikzset
{
highlight/.style n args = 3%<--
{
ellipse,
inner sep = 0mm,
draw = blue,
dashed,
very thick,
label = {[#2, blue]#1:\c@iskustvo@highlight@font@tl #3}
}
}
\makeatother
\begin{document}
\begin{tikzpicture}
\node (node_to_highlight) [minimum size = 1cm, draw] at (0, 0) {};
\node (highlight) [highlight = {210}{below left}{1}, fit = (node_to_highlight)] {};
\end{tikzpicture}
\end{document}
A side note: the convention for naming variables is \⟨scope⟩_⟨module⟩_⟨name⟩_⟨type⟩. ⟨scope⟩ is either local, global, or constant, ⟨module⟩ should be the prefix of the package your are writing or something else unique for your code, ⟨name⟩ is a descriptive name for the variable, and ⟨type⟩ is the type of the variable. In your case, it's a constant (because you used \tl_const:Nn), you left out a module name so I used your user name, iskustvo, the name of the variable is highlight_font, and the type is a token list variable. Putting it all together you have \c_iskustvo_highlight_font_tl.
\makeatletter. There,:is of category “other” (12), cf. the TeXbook p. 37. – frougon Jul 25 '19 at 10:47babelwith a language that makes:active, like French) the:is catcode12, as frougoun said. – Phelype Oleinik Jul 25 '19 at 12:19