netbirdio/netbird · error

interactive sso login failed: %v

Error message

interactive sso login failed: %v

What it means

In Android interactive login, when IsLoginRequired returns true, foregroundGetTokenInfo runs the SSO flow: it obtains a session/code request from management, opens the browser via the injected URLOpener, and exchanges the result for a user JWT. Any failure in that chain (user cancels, opener error, exchange timeout, IdP unavailable, Android TV flow issues) is wrapped here with %v.

Source

Thrown at client/android/login.go:170

func (a *Auth) login(urlOpener URLOpener, isAndroidTV bool) error {
	authClient, err := auth.NewAuth(a.ctx, a.config.PrivateKey, a.config.ManagementURL, a.config)
	if err != nil {
		return fmt.Errorf("failed to create auth client: %v", err)
	}
	defer authClient.Close()

	// check if we need to generate JWT token
	needsLogin, err := authClient.IsLoginRequired(a.ctx)
	if err != nil {
		return fmt.Errorf("failed to check login requirement: %v", err)
	}

	jwtToken := ""
	email := ""
	if needsLogin {
		tokenInfo, err := a.foregroundGetTokenInfo(authClient, urlOpener, isAndroidTV)
		if err != nil {
			return fmt.Errorf("interactive sso login failed: %v", err)
		}
		jwtToken = tokenInfo.GetTokenToUse()
		email = tokenInfo.Email
	}

	err, _ = authClient.Login(a.ctx, "", jwtToken)
	if err != nil {
		return fmt.Errorf("login failed: %v", err)
	}

	// Stored after Login, not before: a rejected token must not leave a hint
	// pointing at an account that cannot be used.
	if email != "" && a.cfgPath != "" {
		if err := writeProfileEmail(a.cfgPath, email); err != nil {
			log.Warnf("failed to store profile account email: %v", err)
		}
	}

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Retry the flow: many failures are user cancellation or transient IdP issues.
  2. Verify the URLOpener works on the target device (register the redirect scheme/intent filter on Android).
  3. Check management and IdP configuration (redirect URI, client ID) if the failure is repeatable at the same step.
Defensive patterns

Strategy: try-catch

Type guard

func isInteractiveSSOFailure(err error) bool {
    return err != nil && strings.HasPrefix(err.Error(), "interactive sso login failed:")
}

Try / catch

err := a.login(urlOpener, isAndroidTV)
if err != nil && isInteractiveSSOFailure(err) {
    // covers user cancellation, opener failure, token exchange timeout:
    // offer a retry; if it always fails at the same step, check redirect/
    // intent-filter registration and IdP configuration
}

Prevention

When it happens

Trigger: User closing the browser or canceling before completing SSO; URLOpener implementation failing (especially on Android TV); token exchange request expiring; IdP outage or misconfigured redirect.

Common situations: Deep-link/custom-scheme redirect not registered for the app; TV devices where no browser is available; clock skew or expired flow state in the token exchange.

Related errors


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