{"record":{"id":"8c78837519f7bd3e","repo":"netbirdio/netbird","slug":"interactive-sso-login-failed-v-8c7883","errorCode":null,"errorMessage":"interactive sso login failed: %v","messagePattern":"interactive sso login failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/android/session.go","lineNumber":302,"sourceCode":"\t}\n\tengine := cc.Engine()\n\tif engine == nil {\n\t\treturn fmt.Errorf(\"engine is not initialized\")\n\t}\n\n\tauthClient, err := auth.NewAuth(ctx, cfg.PrivateKey, cfg.ManagementURL, cfg)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create auth client: %v\", err)\n\t}\n\tdefer authClient.Close()\n\n\t// Passing the config path makes the flow pick up the login_hint: an extend\n\t// renews the session of the account already signed in, so it must not stop to\n\t// offer a choice.\n\ta := NewAuthWithConfig(ctx, cfg, cfgPath)\n\ttokenInfo, err := a.foregroundGetTokenInfo(authClient, urlOpener, isAndroidTV)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"interactive sso login failed: %v\", err)\n\t}\n\n\tif _, err := engine.ExtendAuthSession(ctx, tokenInfo.GetTokenToUse()); err != nil {\n\t\treturn err\n\t}\n\tc.clearLoginRequired()\n\n\tgo urlOpener.OnLoginSuccess()\n\treturn nil\n}\n","sourceCodeStart":284,"sourceCodeEnd":313,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/android/session.go#L284-L313","documentation":"This wraps a failure of foregroundGetTokenInfo, the interactive SSO step of a session extend on Android. The flow drives a browser-based (or Android TV code-entry) OAuth exchange against the IdP via the URLOpener callbacks; any failure before a usable token is obtained — user cancellation, browser open failure, IdP or management connectivity loss, or the device-flow timing out — surfaces here.","triggerScenarios":"urlOpener.OpenURL fails or the user closes the browser/tab without completing login; the IdP rejects the request (expired client registration, redirect mismatch, IdP outage); management connection drops between NewAuth and the token request; Android TV flow where the user never enters/finishes the verification code; flow deadline exceeded waiting for token polling.","commonSituations":"User dismisses the login prompt (cancel button on the expiry notification); default browser on a managed device blocks the custom redirect; IdP sign-in policy requires MFA the device cannot complete; captive/limited network where the IdP domain is blocked but management is reachable.","solutions":["Check the inner error string: 'canceled' means user abort (harmless, retry from UI), connectivity messages mean network/IdP reachability","Verify the IdP and management are both reachable from the device, then retry the extend — the flow is idempotent","On Android TV, ensure the user completes the code entry at the shown URL within the stated time window","If the browser never opens, check that urlOpener.OpenURL receives an https URL and a default handler exists (disable per-app browser restrictions)","Persistent failure with an IdP error code: review the IdP application configuration (client ID, redirect URI) in the management setup"],"exampleFix":"// before: single attempt surfaces as opaque 'interactive sso login failed'\nreturn fmt.Errorf(\"interactive sso login failed: %v\", err)\n\n// after: keep the cause but distinguish user cancellation for the UI layer\nif errors.Is(err, context.Canceled) {\n    return err // let the UI show 'sign-in canceled' instead of an error\n}\nreturn fmt.Errorf(\"interactive sso login failed: %v\", err)","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// In the caller of extendAuthSession:\nif err := c.extendAuthSession(ctx, opener, isTV); err != nil {\n    if errors.Is(err, context.Canceled) || strings.Contains(err.Error(), \"canceled\") {\n        notifyUser(\"Sign-in canceled\") // not an error condition\n        return nil\n    }\n    if strings.Contains(err.Error(), \"interactive sso login failed\") {\n        notifyRetryable(err) // network/IdP issue; user can tap retry\n        return nil\n    }\n    return err\n}","preventionTips":["Show the inner cause in the UI — 'canceled' vs 'cannot reach server' need different user actions","Only present the extend prompt when the device has working connectivity to both management and the IdP domain","For TV flows, display the code deadline and disable the button after expiry to avoid guaranteed timeouts"],"tags":["android","sso","oauth","login","mobile","user-cancel"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}