Long Lived access tokens revocation

My component generates an LLAT to give to my devices - they use the rest api to update state real time.

I can’t see a way to revoke an LLAT, only the refresh_token that was used to generate it, when i boot, (and periodically) i remove the refresh_token.

My question is - does this removal/revocation of the refresh_token automatically flush the LLAT or does that flush only happen when the LLAT expires?

Check the theme you’re using, next to all my LLATs I see a trashcan icon.

thanks - i’m doing this with hass.auth under the hood

The UI delete option that @Tinkerer mentions calls the auth/delete_refresh_token webservice too, so looks like this is the only method.

Looking through the code it looks like a LLAT is just a refresh token with a long expiry so I guess it is just a terminology difference and deleting refresh token is deleting the LLAT.

Delete code from UI - /src/panels/profile/ha-long-lived-access-tokens-card.ts

try {
      await this.hass.callWS({
        type: "auth/delete_refresh_token",
        refresh_token_id: token.id,
      fireEvent(this, "hass-refresh-tokens");
    } catch (err: any) {
      await showAlertDialog(this, {
        title: this.hass.localize(
        text: err.message,

Core code to create tokens - homeassistant/auth/init.py

        if user.system_generated != (token_type == models.TOKEN_TYPE_SYSTEM):
            raise ValueError(
                "System generated users can only have system type refresh tokens"

        if token_type == models.TOKEN_TYPE_NORMAL and client_id is None:
            raise ValueError("Client is required to generate a refresh token.")

        if (
            token_type == models.TOKEN_TYPE_LONG_LIVED_ACCESS_TOKEN
            and client_name is None
            raise ValueError("Client_name is required for long-lived access token")

        if token_type == models.TOKEN_TYPE_LONG_LIVED_ACCESS_TOKEN:
            for token in user.refresh_tokens.values():
                if (
                    token.client_name == client_name
                    and token.token_type == models.TOKEN_TYPE_LONG_LIVED_ACCESS_TOKEN
                    # Each client_name can only have one
                    # long_lived_access_token type of refresh token
                    raise ValueError(f"{client_name} already exists")

        return await self._store.async_create_refresh_token(

Thanks very much for this - i’d reviewed auth/init.py but the frontend you’ve pointed to confirms my approach.

Appreciate yours and @Tinkerer’s help.

1 Like

a followup to this, in case anybody else experiences the same issue

Users need to be admins to post to the RestAPI with a LLAT.