[Bug] nodes are duplicated after expiry and reauth #1047

Closed
opened 2025-12-29 02:27:55 +01:00 by adam · 7 comments
Owner

Originally created by @bobelev on GitHub (Jun 20, 2025).

Is this a support request?

  • This is not a support request

Is there an existing issue for this?

  • I have searched the existing issues

Current Behavior

A new node is created when the user performs a re-auth after the node has expired.

Expected Behavior

Reauthenticated users should not create new nodes.

Steps To Reproduce

oicd config

oidc:
  only_start_if_oidc_is_available: true
  issuer: …
  client_id: headscale-users
  expiry: 4d
  use_expiry_from_token: false
  scope: ["openid", "profile", "email"]
  allowed_groups:
  - vpn-users

Environment

- OS: 24.04
- Headscale version: 0.26.0
- Tailscale version: 0.82.•

Runtime environment

  • Headscale is behind a (reverse) proxy
  • Headscale runs in a container

Debug information

I've dumped current nodes from my installation and printed duplicates:

duplicates: dict[str, list[Node]] = {}
    for node_data in data:
        node = Node(**node_data)
        if node.machine_key not in duplicates:
            duplicates[node.machine_key] = []
        duplicates[node.machine_key].append(node)

    for mk, nodes in duplicates.items():
        if len(nodes) > 1:
            print(f'{mk[:10]} has {len(nodes)} nodes')
            for node in nodes:
                print(f'\t{node.given_name}:'
                      f' last_seen:{datetime.fromtimestamp(node.last_seen["seconds"])}'
                      f' expiry:{datetime.fromtimestamp(node.expiry["seconds"])}'
                      f' created_at:{datetime.fromtimestamp(node.created_at["seconds"])}')
mkey:e826b has 2 nodes
	somebody-ckdxrp1y: last_seen:2025-06-20 00:54:55 expiry:2025-06-20 09:46:44 created_at:2025-06-16 09:46:44
	somebody-m5joip2c: last_seen:2025-06-20 10:33:31 expiry:2025-06-24 09:55:47 created_at:2025-06-20 09:55:47

mkey:17409 has 2 nodes
	someoneelse-q6lr-lqanoetd: last_seen:2025-06-20 10:43:48 expiry:2025-06-24 10:46:23 created_at:2025-06-20 10:46:24
	someoneelse-q6lr-ldubzxhv: last_seen:2025-06-20 10:54:42 expiry:2025-06-24 10:49:42 created_at:2025-06-20 10:49:42
Originally created by @bobelev on GitHub (Jun 20, 2025). ### Is this a support request? - [x] This is not a support request ### Is there an existing issue for this? - [x] I have searched the existing issues ### Current Behavior A new node is created when the user performs a re-auth after the node has expired. ### Expected Behavior Reauthenticated users should not create new nodes. ### Steps To Reproduce oicd config ``` oidc: only_start_if_oidc_is_available: true issuer: … client_id: headscale-users expiry: 4d use_expiry_from_token: false scope: ["openid", "profile", "email"] allowed_groups: - vpn-users ``` ### Environment ```markdown - OS: 24.04 - Headscale version: 0.26.0 - Tailscale version: 0.82.• ``` ### Runtime environment - [x] Headscale is behind a (reverse) proxy - [ ] Headscale runs in a container ### Debug information I've dumped current nodes from my installation and printed duplicates: <details> ``` duplicates: dict[str, list[Node]] = {} for node_data in data: node = Node(**node_data) if node.machine_key not in duplicates: duplicates[node.machine_key] = [] duplicates[node.machine_key].append(node) for mk, nodes in duplicates.items(): if len(nodes) > 1: print(f'{mk[:10]} has {len(nodes)} nodes') for node in nodes: print(f'\t{node.given_name}:' f' last_seen:{datetime.fromtimestamp(node.last_seen["seconds"])}' f' expiry:{datetime.fromtimestamp(node.expiry["seconds"])}' f' created_at:{datetime.fromtimestamp(node.created_at["seconds"])}') ``` </details> ``` mkey:e826b has 2 nodes somebody-ckdxrp1y: last_seen:2025-06-20 00:54:55 expiry:2025-06-20 09:46:44 created_at:2025-06-16 09:46:44 somebody-m5joip2c: last_seen:2025-06-20 10:33:31 expiry:2025-06-24 09:55:47 created_at:2025-06-20 09:55:47 mkey:17409 has 2 nodes someoneelse-q6lr-lqanoetd: last_seen:2025-06-20 10:43:48 expiry:2025-06-24 10:46:23 created_at:2025-06-20 10:46:24 someoneelse-q6lr-ldubzxhv: last_seen:2025-06-20 10:54:42 expiry:2025-06-24 10:49:42 created_at:2025-06-20 10:49:42 ```
adam added the bugOIDC labels 2025-12-29 02:27:55 +01:00
adam closed this issue 2025-12-29 02:27:56 +01:00
Author
Owner

@spymobilfon commented on GitHub (Jun 20, 2025):

Yes, I have the same issue

@spymobilfon commented on GitHub (Jun 20, 2025): Yes, I have the same issue
Author
Owner

@nblock commented on GitHub (Jun 21, 2025):

A new node is created when the user performs a re-auth after the node has expired.

Does this also create a new user after reauth or just a new node assigned to a previously existing user?

@nblock commented on GitHub (Jun 21, 2025): > A new node is created when the user performs a re-auth after the node has expired. Does this also create a new user after reauth or just a new node assigned to a previously existing user?
Author
Owner

@bobelev commented on GitHub (Jun 23, 2025):

The user stays the same. I found where the issue is. When we use GetNodeByMachineKey in RegisterNode, it only returns the first match in the database. But it should actually return a list of nodes.

After I upgraded from 0.23 to the latest version, I still have some leftover users and nodes with the same machine keys. Code checks new oidc users against existing legacy users and decides to create a new node.

I guess this is also not very good for new installations because users can change accounts within the same machine.

@bobelev commented on GitHub (Jun 23, 2025): The user stays the same. I found where the issue is. When we use `GetNodeByMachineKey` in `RegisterNode`, it only returns the first match in the database. But it should actually return a list of nodes. After I upgraded from 0.23 to the latest version, I still have some leftover users and nodes with the same machine keys. Code checks new oidc users against existing legacy users and decides to create a new node. I guess this is also not very good for new installations because users can change accounts within the same machine.
Author
Owner

@uonr commented on GitHub (Jul 6, 2025):

@nblock

Does this also create a new user after reauth or just a new node assigned to a previously existing user?

In my case, it creates a new user after reauth, should I open a new issue and there are any workaround?

After reauth:

100.64.0.52     susumi               me@          macOS   -

Before:

100.64.0.20     troia                me.yuru.me   windows offline
100.64.0.33     troie                me.yuru.me   windows offline
100.64.0.10     uilp                 me.yuru.me   iOS     -
@uonr commented on GitHub (Jul 6, 2025): @nblock > Does this also create a new user after reauth or just a new node assigned to a previously existing user? In my case, it creates a new user after reauth, should I open a new issue and there are any workaround? After reauth: ``` 100.64.0.52 susumi me@ macOS - ``` Before: ``` 100.64.0.20 troia me.yuru.me windows offline 100.64.0.33 troie me.yuru.me windows offline 100.64.0.10 uilp me.yuru.me iOS - ```
Author
Owner

@uonr commented on GitHub (Jul 6, 2025):

@nblock

Does this also create a new user after reauth or just a new node assigned to a previously existing user?

In my case, it creates a new user after reauth, should I open a new issue and there are any workaround?

After reauth:

100.64.0.52     susumi               me@          macOS   -

Before:

100.64.0.20     troia                me.yuru.me   windows offline
100.64.0.33     troie                me.yuru.me   windows offline
100.64.0.10     uilp                 me.yuru.me   iOS     -

I fixed this issue. Because NixOS skipped Headscale 0.24 between two stable releases, the map_legacy_users option was disabled before it had a chance to be enabled. Manually enabling it resolved the problem.

@uonr commented on GitHub (Jul 6, 2025): > [@nblock](https://github.com/nblock) > > > Does this also create a new user after reauth or just a new node assigned to a previously existing user? > > In my case, it creates a new user after reauth, should I open a new issue and there are any workaround? > > After reauth: > > ``` > 100.64.0.52 susumi me@ macOS - > ``` > > Before: > > ``` > 100.64.0.20 troia me.yuru.me windows offline > 100.64.0.33 troie me.yuru.me windows offline > 100.64.0.10 uilp me.yuru.me iOS - > ``` I fixed this issue. Because NixOS skipped Headscale 0.24 between two stable releases, the map_legacy_users option was disabled before it had a chance to be enabled. Manually enabling it resolved the problem.
Author
Owner

@kradalby commented on GitHub (Sep 10, 2025):

After I upgraded from 0.23 to the latest version, I still have some leftover users and nodes with the same machine keys. Code checks new oidc users against existing legacy users and decides to create a new node.

Did this mean you skipped over everything in between? did you look at the map_legacy_users option mentioned in the previous comment?

@kradalby commented on GitHub (Sep 10, 2025): > After I upgraded from 0.23 to the latest version, I still have some leftover users and nodes with the same machine keys. Code checks new oidc users against existing legacy users and decides to create a new node. Did this mean you skipped over everything in between? did you look at the `map_legacy_users` option mentioned in the previous comment?
Author
Owner

@kradalby commented on GitHub (Sep 12, 2025):

I'm going to close this as most likely an issue of skipping versions which had changelog notes about step by step migration.

If this is not the case, and the issue persist in the next release, open a new issue with as much debug info as possible.

@kradalby commented on GitHub (Sep 12, 2025): I'm going to close this as most likely an issue of skipping versions which had changelog notes about step by step migration. If this is not the case, and the issue persist in the next release, open a new issue with as much debug info as possible.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/headscale#1047