Reading sensors using a REST API that requires a bearer token : I'm totally lost

Hello everyone,

New to the forum, but happy user of HA for more than a year now.

Would anyone have a complete example on how to “GET” data that requires a “Bearer token” in the Authorization of the request ? I can’t find a way to map a curl commands workflow to HA sensors.

One of my appliances has a REST API (and I don’t want to use the vendor’s app to read these values, I have a nice dashboard). These two curl commands work fine from the CLI :

# Authentication
curl -X 'POST' 'https://myvendor.com/path-to-token' -H 'Content-Type: application/json' -d '{"userName":"", “password":""}' 

# Sensors 
curl -X 'GET' 'https://myvendor.com/path/to/the/list/of/sensors?id=<myuserid>' -H 'accept: */*' -H 'Authorization: Bearer <token>'

In configuration.yaml, I tried rest, rest_command, restful sensors … to no avail. I’m lost, totally … :frowning: Been through docs, Google, Github examples (even asked ChatGPT for a good laugh), but I couldn’t find anything that looks like what I’m trying to achieve (and some “successful” forum entries made me think of the “Rest of the owl” subreddit …).

My token is always empty, so I can’t even start reading values :frowning:

Latest attempt:

rest:
  - resource: "https://https://myvendor.com/path-to-token"
    method: POST
    payload: '{"userName": "N is uppercase", "password": "hardcoded, YOLO"}'
    headers:
      Content-Type: "application/json"
    sensor:
      - name: "token"
        value_template: "{{ value_json.data.token }}"
      - name: "refresh_token"
        value_template: "{{ value_json.data.tokenExpiringdata }}"
  - sensor:
      - name: "Bearer"
        state: "{{ states('sensor.token') }}"
      - name: "Refresh"
        state: "{{ states('sensor.refresh_token') }}"

Restarted HA, even rebooted, but the sensor values are empty :frowning: So I can’t even try the second step either :frowning:

I also tried with restful commands, still no joy. I tried hardcoding name and password in the config file, no luck either.

Would anyone have a similar working config I can get inspired from ?

I have an code i used for grocy, also with the same authentication.

here it is, maybe it helps you getting in the right direction.

rest:
  - authentication: basic
    scan_interval: 86400 # in s ... set to once a day to save memory space
    resource: http://XX.XX.XXX:9192/api/stock/volatile?due_soon_days=2
    method: GET
    headers:
      GROCY-API-KEY: XXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    sensor:
    - name: grocy_expire_2_days
      unique_id: d0f55f50-f68a-42e2-838f-b57b7127125e
      value_template: 'OK'
      json_attributes:
        - "due_products"
        - "overdue_products"
        - "expired_products"

  - authentication: basic
    scan_interval: 86400 # in s ... set to once a day to save memory space
    resource: http://XX.XX.XXX:9192/api/stock/volatile?due_soon_days=5
    method: GET
    headers:
      GROCY-API-KEY: XXXXXXXXXXXXXXXXXXXXX
    sensor:
    - name: grocy_expire_5_days
      unique_id: bdde829f-XXXXXXXXXXXXXXXXXXXX
      value_template: 'OK'
      json_attributes:
        - "due_products"
        - "overdue_products"
        - "expired_products"

Also i did look at your code, i think you have a typo:

value_json.data.tokenExpiringdata

I think should be, just guessing, but aso i did change the code a bit as the URL in the resource field has a duplicate “https://” part. It should be corrected to a single “https://”.

value_json.data.tokenExpiringDate
rest:
  - resource: "https://myvendor.com/path-to-token"
    method: POST
    payload: '{"userName": "N is uppercase", "password": "hardcoded, YOLO"}'
    headers:
      Content-Type: "application/json"
    sensor:
      - name: "token"
        value_template: "{{ value_json.data.token }}"
      - name: "refresh_token"
        value_template: "{{ value_json.data.tokenExpiringDate }}"  # Corrected path
  - sensor:
      - name: "Bearer"
        state: "{{ states('sensor.token') }}"
      - name: "Refresh"
        state: "{{ states('sensor.refresh_token') }}"

Thanks for your reply :slight_smile:

The URL and JSON are not the real ones, I’m just protecting the innocent :slight_smile: So yeah, there’s a typo here, but in my code I’m using the right names.

Your code is really interesting, especially on how you get the different sensor values, and it will most likely help me to get one notch closer to my solution … but I’m stuck at the phase just before, where I’m trying to get and store the token (I may have found something in the logs though, the token is 1500+ characters long, and HA can’t handle more than 255 :confused: Probably what’s happening here … )

BTW, did you create the unique ID yourself, or was it auto-assigned by HA ?

Cheers,
Flaf ’

Yep, just as I suspected : the token is too long (1509 bytes !). So I can’t store it in a sensor state :confused: I set the state to a shorter part of the json packet, and it works fine ! So that’s one part of the puzzle solved (even though I don’t feel any closer to the solution, I now need to see how to store the token in an attribute … )

Getting closer … So the token is more than 255 characters, and can’t be a state. So I made it an attribute :

rest:
  - resource: "https://myvendor.com/path-to-token"
    method: POST
    payload: '{"userName": "say my name", "password": "don't dance to this"}'
    headers:
      Content-Type: "application/json"
    sensor:
      - name: "refresh_token"
        value_template: "{{ value_json.data.tokenExpiringdata }}"
        json_attributes_path: $.data
        json_attributes:
          - token

sensor.refresh_token.token now stores my 1509 bytes token :slight_smile:

And this is now where I get stuck :

sensor:
  - platform: rest
    name: "appliance details"
    resource: "https://myvendor.com/path/to/the/list/of/sensors?id=<myuserid>'"
    method: GET
    headers:
      Authorization: "Bearer {{ states.refresh_token.token }}"

I’m getting a response “you’re not authorized” :confused:

On to more troubleshooting I guess …

I guess my work here is done, it works !

template:
  - sensor:
      - name: appliance_sensor1
        state: "{{ state_attr ('sensor.appliance','sensor1') }}"
  - sensor:
      - name: appliance_sensor2
        state: "{{ state_attr ('sensor.appliance','sensor2') }}"
  - sensor:
      - name: appliance_sensor3
        state: "{{ state_attr ('sensor.appliance','sensor3') }}"
  - sensor:
      - name: appliance_sensor4
        state: "{{ state_attr ('sensor.appliance','sensor4') }}"

rest:
  - resource: "https://myvendor.com/path-to-token"
    method: POST
    payload: '{"userName": "you can call me Al", "password": "secrets are so overrated"}'
    headers:
      Content-Type: "application/json"
    sensor:
      - name: "token"
        value_template: "{{ value_json.data.tokenExpiringdata }}"
        json_attributes_path: $.data
        json_attributes:
          - token

  - resource: "https://myvendor.com/path/to/the/list/of/sensors?id=<myuserid>"
    method: GET
    headers:
      Authorization: "Bearer {{ state_attr('sensor.token','token')}}"
      Accept: "*/*"
    sensor:
      - name: appliance
        value_template: "{{ value_json.data.one_of_useless_attributes }}"
        json_attributes_path: $.data
        json_attributes:
          - sensor1
          - sensor2
          - sensor3
          - sensor4

The templates create sensors from the REST GET request. These can then be added as regular sensors in HA.

The first REST resource gets the token, but as it is longer than 255 characters, it is saved as an attribute of the sensor “token”. And then, the second REST resource creates the “appliance” sensor, and uses the state_attr function to concatenate “Bearer” and the token for the authorization. The attributes are fields from the REST request response.

Hope this will help save some time to someone in the future.

2 Likes