To help the next person, I found a work-around: use loops over a list of dict as a way to "inject" variables into the template.
So I needed something like {{ vars[prefix + 'readonly_token'] }}, {{ vars[prefix + 'readwrite_token'] }}, {{ vars[prefix + 'readonly_tokensecret'] }}, {{ vars[prefix + 'readwrite_tokensecret'] }} in the template.
In the same play, I also needed to instantiate the template for multiple values of 'prefix', each prefix can be a different hostname or mapped to the same hostname like "prefix: {{ another_prefix }}".
The fact that prefix can be mapped to another prefix is way breaks the syntax "{{ vars[prefix + 'readonly_token'] }}".
So the work-around is like this:
vars:
host1: { readonly_token: "blah", readwrite_token: "blah", readonly_tokensecret: "blah", readwrite_tokensecret: "blah" }
host2: { readonly_token: "blah", readwrite_token: "blah", readonly_tokensecret: "blah", readwrite_tokensecret: "blah" }
host3: { readonly_token: "blah", readwrite_token: "blah", readonly_tokensecret: "blah", readwrite_tokensecret: "blah" }
host4: { readonly_token: "blah", readwrite_token: "blah", readonly_tokensecret: "blah", readwrite_tokensecret: "blah" }
list_of_all_hosts: [ "{{ host1 }}", "{{ host2 }}", "{{ host3 }}", "{{ host4 }}" ]
template:
src: template file
dest: blah
with_items: "{{ list_of_all_hosts }}"
In the template file, instead of {{ vars[prefix + 'readonly_token'] }} I can then use {{ item.readonly_token }} and the dict mapping ensure proper values for me.
The loop inject "updated values" for me into the template for each run, as if I can re-define a variable for each template call.
I see using template with loop over a dict as a way to inject variable into the template instead of the usual way to create variable (default role var, group var, host var, role var, commandline var ....)