xperimental / netatmo-exporter

Prometheus exporter for Netatmo sensor data.
MIT License
44 stars 18 forks source link

oauth2: invalid_grant error when refreshing token #60

Open tukane opened 2 months ago

tukane commented 2 months ago

Hi,

i noticed, that the authorization is not working anymore.

The docker log says: level=error msg="Error during refresh: Get \"https://api.netatmo.net//api/getstationsdata?app_type=app_station\": oauth2: \"invalid_grant\""

Did Netatmo changed the authorization again?

Greetings tukane

xperimental commented 2 months ago

I am not aware of any changes and, so far, my exporter seems to run fine.

I'll have a look the coming days, the only thing I can think of right now is whether you have selected the correct scope when creating the initial token.

DEEJCUK commented 2 months ago

I am seeing similar issues today, refreshing either by the built in GUI or by the api and copy token results in

netatmo-exporter  | level=info msg="Listen on :9210..."
netatmo-exporter  | level=error msg="Error during refresh: no token available"
DEEJCUK commented 2 months ago

ok a bit of a breakthrough for me, i went from latest docker image to master, pulled, and restarted, reauth'd, restarted container 2nd time and its started working for me

xperimental commented 2 months ago

@DEEJCUK Good that your issue is fixed. latest and master are "nearly identical" at the time of writing, though.

But you are giving me an idea there: Docker does not automatically update the local image when the repository has a newer one with the same tag (for example latest or master, which get "reused").

@tukane Can you check which version of the exporter you are running? Maybe you have the same issue as @DEEJCUK and have just pulled the exporter in a previous version that does not work anymore (if you're using Docker at all).

DEEJCUK commented 2 months ago

i noticed in the first comment there is a double slash in the URL after .net is this relevant ?

level=error msg="Error during refresh: Get "[https://api.netatmo.net//api/getstationsdata?app_type=app_station\](https://api.netatmo.net//api/getstationsdata?app_type=app_station%5C)": oauth2: "invalid_grant""
xperimental commented 2 months ago

No, I don't think the double slash has anything to do with this issue. While it is wrong, they are usually collapsed to a single slash on the server side.

I was able to reproduce the invalid_grant error message with a token that I generated a long time ago and never refreshed. A freshly generated token works fine, same for my long-running exporter which regularly refreshes the token.

@tukane Do you have any update on your situation?

tukane commented 2 months ago

Hi all, I changed the docker image from "latest" to "master". Created a new token for the token-file and restarted the container, but the error message remains the same:

level=warning msg="Restored token has no expiry time! Token will be renewed immediately."
level=info msg="Loaded token from /var/lib/netatmo-exporter/netatmo-token.json."
level=info msg="Listen on :9210..."
level=debug msg="Refreshing data. Time since last refresh: 2562047h47m16.854775807s"
level=error msg="Error during refresh: Get \"https://api.netatmo.net//api/getstationsdata?app_type=app_station\": oauth2: \"invalid_grant\""
lennartp92 commented 2 months ago

I'm having this issue, too. The container suddenly did not push data anymore. It still does not work after creating a new token and using the "master" instead of the "latest" image. 

xperimental commented 2 months ago

@lennartp92 Can you tell me what version of netatmo-exporter you are running? latest and master are both moving tags and, at this time of writing, both contain the 2.0.1 version released in October last year.

Docker (and other container runtimes) by default do not re-download an image if an image of the same name is already present on the host. This means that if you used latest or master in the past on the machine, but did not delete the previous version, it is still using an older release and not the current one.

In general, both latest and master are only provided for convenience, but you should rather use the explicitly versioned tags instead (or make sure to manually pull the images if needed).

My assumption on what happened for @DEEJCUK and @tukane where it started working when switching to master was that they never used "the tag that worked" before, so they got a fresh version.

See if you can replicate the issue with the latest version (ghcr.io/xperimental/netatmo-exporter:2.0.1) and a new token. If that still returns an error, then there's something broken that I need to fix.

Btw: While the exporter is running, there's also a /version handler available that will return "what it knows about itself". I need to change the exporter so that it also prints out this information during startup for easier debugging ...

DEEJCUK commented 2 months ago

my workflow went something like this :

look up the container with docker ps and stop the container, then you can delete it with docker rm <containername> and then delete the image using docker rmi <imagename> and then rerun docker pull <imagename> to pull the latest image i also run docker system prune to remove all traces of containers, networks etc no longer connected

but please make sure you read about these commands before running to ensure they are suitable for your use case

xperimental commented 2 months ago

If the exporter is still running, first try to check the currently running version using the /version endpoint :slightly_smiling_face:

tukane commented 2 months ago

My workflow was nearly the same, but I use portianer to manage my containers. I deleted the old container and the image with the latest/master tag and pulled explicit the version 2.0.1 from the repo, but the error message remains the same.

As I am using docker-compose, how can I add the /version handler?

xperimental commented 2 months ago

As I am using docker-compose, how can I add the /version handler?

The handler is available as an HTTP endpoint from the exporter. Similar to how Prometheus uses /metrics to get the metrics data you can use a HTTP client (Browser, curl, ...) to get the information from /version by pointing your client to the URL where the exporter is available, for example http://192.168.0.20/version if the exporter is running at that IP address.

edit: Just remembered that the exporter also has a very simple interface at / which shows the current token and also allows you to log in, if the token is not present. You could try that as another way of getting the token into your installation.

xperimental commented 2 months ago

@tukane Something completely different: I have read the documentation about the error in the developer docs (I know, should have done this earlier). It says this error should indicate a mismatch in the configuration between what is configured in the console and what the application is using.

Can you have a look in the NetAtmo developer console. Do you have something specified as "redirect URI" or "webhook URI"? If yes, can you try setting those fields to an empty value and try again?

tukane commented 2 months ago

Thanks for clarification. Here is the output of the /version page:

version "2.0.1"
commit  "57952a2c2070406ea26f1c3b17930eba9c9c744a"

The redirect URI and web hook URI field are empty in the dev console from Netatmo.

BTW: When I try to open the web interface to enter the token there, I also get the Error getting token: oauth2: "invalid_grant"error message.

Just for reference, here is my docker-compose file.

version: "3.8"
services:
  netatmo:
    image: xperimental/netatmo-exporter:2.0.1
    container_name: netatmo
    ports:
      - 8040:8080
      - 9210:9210
    volumes:
      - /opt/netatmo:/var/lib/netatmo-exporter/
      - /opt/netatmo/netatmo-token.json:/var/lib/netatmo-exporter/netatmo-token.json
    environment:
      - NETATMO_CLIENT_ID= <my ID>
      - NETATMO_CLIENT_SECRET= <my secret>
      - NETATMO_EXPORTER_ADDR=:9210
      # - NETATMO_EXPORTER_TOKEN_FILE=/var/lib/netatmo-exporter/netatmo-token.json
      - NETATMO_EXPORTER_EXTERNAL_URL=http://192.168.0.140:9210
      - DEBUG_HANDLERS=
      - NETATMO_LOG_LEVEL=debug
      - NETATMO_REFRESH_INTERVAL=1m
      - NETATMO_AGE_STALE=60m
    restart: unless-stopped
    network_mode: bridge
networks: {}
DEEJCUK commented 2 months ago

here is mine, its a bit less than yours, but its working

 netatmo-exporter:
    container_name: netatmo-exporter
    image: ghcr.io/xperimental/netatmo-exporter:master
    restart: unless-stopped
    environment:
      - NETATMO_CLIENT_ID=${NETATMO_CLIENT_ID}
      - NETATMO_CLIENT_SECRET=${NETATMO_CLIENT_SECRET}
      - NETATMO_EXPORTER_EXTERNAL_URL=http://XXX.XXX.XXX.XXX:9210
    ports:
      - "9210:9210"

and my version is {"version":"2.0.0-3-g57952a2","commit":"57952a2c2070406ea26f1c3b17930eba9c9c744a"}

xperimental commented 1 month ago

@tukane Sorry, forgot to reply earlier.

One thing I find odd about your configuration is having the two volume mounts "inside of each other". Just having the volume for the directory should suffice.

I can see that you have the "external URL" set. Have you tried the "interactive authentication" using the exporter's web interface already? (The "login" link, not the textbox)

Also, you can see that you are both using the same code (commit 57952a2c...), even though one is using the image built as "2.0.1" (tagged) and the other as "master" (before the tag existed).

tukane commented 1 month ago

@xperimental: Thanks for your annotations, I've deleted the mount for the json file.

I'm not able to reach the web interface. The container is running on a server with the IP 192.168.0.13. So I've tried to open the URL http://192.168.0.13:9210, but I'm getting also the same error message Error getting token: oauth2: "invalid_grant" when I try to access it.

The version 2.0.1 and the latest version are using the same code (commit "57952a2c2070406ea26f1c3b17930eba9c9c744a")

mblaschke commented 3 weeks ago

@xperimental The root cause of this problem is that the new token is only saved on shutdown but never when a new one if fetched from the API.

If the exporter runs for weeks and then is killed (eg. power outage, OOM kill,...) the exporter still has the initial token from the start and lost the updated one.

This happened to me multiple times now. Please regularly update the token file, eg. every hour.

xperimental commented 3 weeks ago

@mblaschke I might have misread the thread so far, but I was under the impression that the failure described here is immediate and not once the exporter has been killed after a longer runtime. The issue you're describing is #54.

mblaschke commented 3 weeks ago

@xperimental not sure 🤔

i was running multiple times into this issue (even today) after i had to restart the physical box and was running into the "oauth2: invalid_grant error when refreshing token" issue. The token was expired and so the exporter was failing.

Log output:

level=info msg="Listen on :9210..."
level=debug msg="Refreshing data. Time since last refresh: 2562047h47m16.854775807s"
level=error msg="Error during refresh: Get \"https://api.netatmo.net//api/getstationsdata?app_type=app_station\": oauth2: \"invalid_grant\""

workaround: restart the container every day or recreate the token every time the server is rebootet

xperimental commented 3 weeks ago

@mblaschke I've already accepted that saving the token after a refresh is probably a good idea for people that have issues with spontaneous power outages or other circumstances which cause the exporter to not be able to save on shutdown. This should not be the normal case "after a restart" though. For me the exporter has survived a lot of restarts already. Is there some special circumstance for you that makes the exporter unable to save the token on shutdown?

mblaschke commented 3 weeks ago

not sure if docker daemons "live restore" causes the issues but it's definitely not storing the file when the machine reboots. strange.

xperimental commented 2 weeks ago

@mblaschke I have been unaware of that feature and have not used it so far. The documentation is, unfortunately, a bit short on details. There is a section about "Live restore upon restart", but reading that and a few articles about the feature from other sources, I get the feeling this is more about a (docker-)service restart not a machine restart.

xperimental commented 2 weeks ago

@tukane I can reproduce the invalid_grant error with an expired token that also has an expired refresh token. Do you also have this issue after a restart of the exporter as @mblaschke described?

--edit: I have just added a small fix to the exporter, so that it ignores expired tokens on startup. This should make it easier to recover from this situation instead of just producing more errors.

tukane commented 1 week ago

@xperimental I don't know what I'm doing wrong but it's not working after a restart either. I've created a new access and refresh token on the Netatmo website and entered this tokens into the netatmo-token.json file in my docker volume. This is how the file looks like:

{
     "access_token": "xxxxxxxx|yyyyyyy",
     "refresh_token": "xxxxxxxx|yyyyyyy"
}

I've stopped the container, deleted the image and started the container once again.

Here is the log output:

level=debug msg="Got signal: terminated"
level=error msg="Error persisting token: error retrieving token: oauth2: \"invalid_grant\""
level=warning msg="Restored token has no expiry time! Token will be renewed immediately."
level=info msg="Loaded token from /var/lib/netatmo-exporter/netatmo-token.json."
level=info msg="Listen on :9210..."
level=debug msg="Refreshing data. Time since last refresh: 2562047h47m16.854775807s"
level=error msg="Error during refresh: Get \"https://api.netatmo.net//api/getstationsdata?app_type=app_station\": oauth2: \"invalid_grant\""
level=debug msg="Refreshing data. Time since last refresh: 1m59.999039506s"