From 7bf19f7a0c9d9d77b15871d8b8b80c399752ee49 Mon Sep 17 00:00:00 2001 From: Viktor Liu Date: Wed, 12 Aug 2026 21:29:30 +0200 Subject: [PATCH] State the condition on the setup key advice --- client/internal/auth/oauth.go | 6 +++++- client/internal/auth/oauth_test.go | 13 +++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/client/internal/auth/oauth.go b/client/internal/auth/oauth.go index 977398058..3208c1ec9 100644 --- a/client/internal/auth/oauth.go +++ b/client/internal/auth/oauth.go @@ -312,12 +312,16 @@ func IsSSOUnavailable(err error) bool { // WithSetupKeyAdvice appends enrollment guidance to an SSO-unavailable error and returns any // other error unchanged. Only enrollment can fall back to a setup key: extending a session and // authenticating SSH cannot, so those paths must not call this. +// +// The login paths that do call it cannot tell an unregistered peer from an SSO-enrolled one +// whose session expired, since both answer PermissionDenied, so the advice names the case it +// applies to rather than telling an enrolled peer to do something that cannot work. func WithSetupKeyAdvice(err error) error { if !IsSSOUnavailable(err) { return err } - return fmt.Errorf("%w. Set this device up with a setup key instead: "+ + return fmt.Errorf("%w. If this device is not enrolled yet, enroll it with a setup key instead: "+ "https://docs.netbird.io/how-to/register-machines-using-setup-keys", err) } diff --git a/client/internal/auth/oauth_test.go b/client/internal/auth/oauth_test.go index 21363cdcb..35752849f 100644 --- a/client/internal/auth/oauth_test.go +++ b/client/internal/auth/oauth_test.go @@ -222,6 +222,19 @@ func TestFallbackFlowRequestAuthInfo(t *testing.T) { }) } +func TestWithSetupKeyAdvice(t *testing.T) { + other := errors.New("connection refused") + assert.Equal(t, other, WithSetupKeyAdvice(other), "only an SSO-unavailable error gets advice") + + advised := WithSetupKeyAdvice(&ssoUnavailableError{msg: "no SSO provider configured"}) + assert.Contains(t, advised.Error(), "no SSO provider configured", "the original message must survive") + assert.Contains(t, advised.Error(), "setup key") + // a setup key cannot re-enrol a peer whose SSO session expired, and the login paths cannot + // tell that peer apart from an unregistered one, so the advice must state its condition + assert.Contains(t, advised.Error(), "not enrolled yet") + assert.True(t, IsSSOUnavailable(advised), "advice must keep the error classifiable") +} + func TestFlowOrder(t *testing.T) { assert.Equal(t, "pkce authorization flow", flowOrder(false)[0].name) assert.Equal(t, "device code flow", flowOrder(true)[0].name)