netbirdio/netbird · error

private services cannot enable bearer auth (SSO): NetBird-on

Error message

private services cannot enable bearer auth (SSO): NetBird-only access and SSO are mutually exclusive

What it means

Returned by Service.validatePrivateRequirements (management/internals/modules/reverseproxy/service/service.go:905). The private-service contract is mutually exclusive with SSO at the service level: NetBird-only access means the overlay's identity already authenticates users, while bearer auth would add a second, external identity layer. Enabling both on the same service is therefore rejected.

Source

Thrown at management/internals/modules/reverseproxy/service/service.go:905

		return s.validateTLSMode()
	default:
		return fmt.Errorf("unsupported mode %q", s.Mode)
	}
}

// validatePrivateRequirements enforces the private-service contract: HTTP mode, ≥1 access group, no bearer auth.
func (s *Service) validatePrivateRequirements() error {
	if !s.Private {
		return nil
	}
	if s.Mode != "" && s.Mode != ModeHTTP {
		return fmt.Errorf("private services only support HTTP mode, got %q", s.Mode)
	}
	if len(s.AccessGroups) == 0 {
		return errors.New("private services require at least one access group")
	}
	if s.Auth.BearerAuth != nil && s.Auth.BearerAuth.Enabled {
		return errors.New("private services cannot enable bearer auth (SSO): NetBird-only access and SSO are mutually exclusive")
	}
	return nil
}

func (s *Service) validateHTTPMode() error {
	if s.Domain == "" {
		return errors.New("service domain is required")
	}
	if s.ListenPort != 0 {
		return errors.New("listen_port is not supported for HTTP services")
	}
	return s.validateHTTPTargets()
}

func (s *Service) validateTCPUDPMode() error {
	if s.Domain == "" {
		return errors.New("domain is required for TCP/UDP services (used for cluster derivation)")
	}

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Choose one model: for NetBird-only access set Private and remove/disable bearer auth.
  2. For SSO-protected public access, keep BearerAuth enabled and leave Private unset.
  3. If you need both identity layers, expose two services (one private, one SSO) rather than combining them.

Example fix

# before
{"name": "app", "private": true, "access_groups": ["grp-ops"],
 "auth": {"bearer_auth": {"enabled": true, "issuer": "https://idp/example"}}}

# after: pick one access model
{"name": "app", "private": true, "access_groups": ["grp-ops"]}
Defensive patterns

Strategy: validation

Validate before calling

if svc.Private && svc.Auth.BearerAuth != nil && svc.Auth.BearerAuth.Enabled {
    return fmt.Errorf("choose one: NetBird-only access (private) or SSO bearer auth")
}

Prevention

When it happens

Trigger: Creating or updating a service that simultaneously has Private: true and Auth.BearerAuth with Enabled: true.

Common situations: Reusing a public SSO-protected service definition and flipping on Private without clearing bearer auth; templates or copied payloads that carry auth blocks into private services; misreading SSO as an additional hardening layer on private services.

Related errors


AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16). Data as JSON: /api/errors/f55aa76b967253cf. Report an issue: GitHub.