Rest sensor - Dynamic Bearer Token (Using Sensor)

Hi everyone,

I am currently facing an issue while trying to retrieve my data through the API using Rest.

The process involves two steps. First, I use my API key to obtain the bearer token, and then I use that bearer token to access the desired data. So far, the initial step is functioning correctly.

For my second request, I am able to utilize my secret file for the header section, but not a sensor value.

My secret file

api_key: "ABC123"
api_key_bearer_static: "Bearer DEF456"

This works

rest:
  - resource: "https://api.com/"
    scan_interval: 3600
    timeout: 60
    method: "POST"
    headers:
      Authorization: !secret api_key_bearer_static
      Content-Type: 'application/json'
      apikey: !secret api_key
    payload: '{"blablabla"}'
    sensor:  
      - name: "Sensor 2"
        value_template: "{{ value_json.prices }}"

This doesn’t work

    headers:
      authorization: >         
        {{states('sensor.api_access_token_bearer')}}

In the developper mode, {{states(‘sensor.api_access_token_bearer’)}} return Bearer DEF456

I tried as well to create a dynamic secret in my secret file, and call this secret, but it doesn’t work as well

secret file:
api_key_bearer_dynamic: '{{ states("sensor.api_access_token_bearer") }}'

config file:
    headers:
      Authorization: !secret api_key_bearer_dynamic

I’ve looked at a lot of the forum, but couldn’t figure out why (since 2021.12 the templating is allowed in header section)

Dynamic Authorization header for REST sensor
Rest Authentication Sensor - #3 by Daryn_L
Restful sensors should support dynamic header templates
https://community.home-assistant.io/t/rest-sensor-templating-in-header-values

So actually found a workaround by not using secrets.
The issue is the token bearer is being refresh every time the home assistant starts, and when running the query to get the prices, the “!secret api_key_bearer_static” is equals to “unknown”

My solution is:

  1. Create helpers as input text where you will store your API key (static) and you bearer key (dynamic) and in my case some static authentication header
  2. Store your bearer token from the API in a sensor
  3. Create an automation that every time the bearer token sensor change value, change the helper text

The new API calls will look like this now:

Getting my bearer token

rest:
 - resource: "https://YOURAPI.com/"
    scan_interval: 36000 #10h
    timeout: 60
    method: "GET"
    headers:
      Authorization: "{{ states('input_text.api_auth_header') }}"
    sensor:  
      - name: "API Access Token Bearer"
        value_template: "Bearer {{ value_json['access_token'] }}"

Getting my price using the bearer token

rest:
   - resource: "https://YOURAPI.com/"
    scan_interval: 3600 #1h
    timeout: 60
    method: "POST"
    headers:
      Authorization: "{{ states('input_text.api_token_bearer') }}"
      Content-Type: "application/json"
      apikey: "{{ states('input_text.api_key') }}"
   sensor:  
      - name: "Sensor"
        value_template: "{{ value_json.prices }}"

The automation will be

alias: Update Token Bearer 
description: "" 
trigger:
  - platform: state 
    entity id:
      - sensor.api_access_token_bearer 
condition: [] 
action:
  - service: input_text.set_value
    data template:
      entity_id: input_text.api_token_bearer 
      value: "{{ trigger.to state.state }}"
mode: single
4 Likes

This seems like a nice solution, but it seems states are limited to 255 characters. This isnt working for the DaikinOne cloud API which returns a much longer access token. Any thoughts?

I had the same problem with token that has more than 255 characters, what I did was similar to @Gautch, but I’m storing the token into multiple 255-character-state sensors. Assuming the token is a little bit more than 510 characters, but it can be any length

rest:
 - resource: "https://YOURAPI.com/"
    method: "POST"
    payload: "{YOUR_CREDENTIALS}"
    sensor:  
      - name: "API Access Token Bearer 1"
        # getting char[0:244]
        value_template: "Bearer {{ value_json['access_token'][:255] }}"
     - name: "API Access Token Bearer 2"
        # getting char[255:509]
        value_template: "Bearer {{ value_json['access_token'][255:510] }}"
     - name: "API Access Token Bearer 3"
        # getting char[510:..]
        value_template: "Bearer {{ value_json['access_token'][510:] }}"

Then in the rest sensor where you adding your authorization simply stack the state of these sensor

...
headers:
    Authorization: "{{states(sensor.API_Access_Token_Bearer_1)}}{{states(sensor.API_Access_Token_Bearer_2)}}{{states(sensor.API_Access_Token_Bearer_3)}}"

I didn’t get the point of copying sensor value to input text.
Why not referencing the sensor directly ?

The limit of 255 characters may be bypassed by storing the token in an attribute and then using state_attr(...) instead of states(...)