From 3689f05407225f8ad29c913e2c5dcfd24b53a85f Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Wed, 14 Jan 2026 08:48:21 +0000 Subject: [PATCH] types: use Username() in User.Proto() when Name is empty User.Proto() was returning u.Name directly, which is empty for OIDC users who have their identifier in the Email field instead. This caused "headscale nodes list" to show empty user names for OIDC-authenticated nodes. Only fall back to Username() when Name is empty, which provides a display-friendly identifier (Email > ProviderIdentifier > ID). This ensures OIDC users display their email while CLI users retain their original Name. Fixes #2972 --- hscontrol/types/users.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/hscontrol/types/users.go b/hscontrol/types/users.go index 36702146..ec40492b 100644 --- a/hscontrol/types/users.go +++ b/hscontrol/types/users.go @@ -174,9 +174,17 @@ func (u UserView) TailscaleUserProfile() tailcfg.UserProfile { } func (u *User) Proto() *v1.User { + // Use Name if set, otherwise fall back to Username() which provides + // a display-friendly identifier (Email > ProviderIdentifier > ID). + // This ensures OIDC users (who typically have empty Name) display + // their email, while CLI users retain their original Name. + name := u.Name + if name == "" { + name = u.Username() + } return &v1.User{ Id: uint64(u.ID), - Name: u.Name, + Name: name, CreatedAt: timestamppb.New(u.CreatedAt), DisplayName: u.DisplayName, Email: u.Email,