From 791923a2cc7b02fe56716ab5fa7e2a80f93c044e Mon Sep 17 00:00:00 2001 From: mlsmaycon Date: Mon, 26 Jan 2026 16:45:09 +0100 Subject: [PATCH 1/2] Fix SSO login on ChromeOS by using Device Code Flow ChromeOS runs Android apps in a container with separate network namespace, preventing the browser from reaching the localhost callback server used by PKCE flow. This causes "service not available" errors after authentication. Use Device Code Flow on ChromeOS (like Android TV) which uses polling instead of localhost callback. On ChromeOS, also auto-open the browser for a similar UX to PKCE while showing QR dialog as fallback. --- .../java/io/netbird/client/MainActivity.java | 24 +++++++++++++++---- .../java/io/netbird/client/PlatformUtils.java | 11 +++++++++ 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/netbird/client/MainActivity.java b/app/src/main/java/io/netbird/client/MainActivity.java index 666b950..c79c3c4 100644 --- a/app/src/main/java/io/netbird/client/MainActivity.java +++ b/app/src/main/java/io/netbird/client/MainActivity.java @@ -73,6 +73,7 @@ private enum ConnectionState { private boolean isSSOFinishedWell = false; private boolean isRunningOnTV = false; + private boolean useDeviceCodeFlow = false; // Last known state for UI updates private ConnectionState lastKnownState = ConnectionState.UNKNOWN; @@ -105,9 +106,13 @@ protected void onCreate(Bundle savedInstanceState) { setSupportActionBar(binding.appBarMain.toolbar); isRunningOnTV = PlatformUtils.isAndroidTV(this); + useDeviceCodeFlow = PlatformUtils.requiresDeviceCodeFlow(this); if (isRunningOnTV) { Log.i(LOGTAG, "Running on Android TV - optimizing for D-pad navigation"); } + if (useDeviceCodeFlow && !isRunningOnTV) { + Log.i(LOGTAG, "Running on ChromeOS - using device code flow for authentication"); + } setVersionText(); @@ -177,7 +182,7 @@ public void onDrawerClosed(View drawerView) { } }); - if (!isRunningOnTV) { + if (!useDeviceCodeFlow) { urlOpener = new CustomTabURLOpener(this, () -> { if (isSSOFinishedWell) { return; @@ -202,11 +207,20 @@ public void open(String url, String userCode) { mBinder.stopEngine(); }); qrCodeDialog.show(getSupportFragmentManager(), "QrCodeDialog"); + + if (!isRunningOnTV) { + try { + Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); + startActivity(browserIntent); + } catch (Exception e) { + Log.e(LOGTAG, "Failed to open browser for device code flow: " + e.getMessage()); + } + } } @Override public void onLoginSuccess() { - Log.d(LOGTAG, "onLoginSuccess fired for TV."); + Log.d(LOGTAG, "onLoginSuccess fired for device code flow."); if (qrCodeDialog != null && qrCodeDialog.isVisible()) { qrCodeDialog.dismiss(); qrCodeDialog = null; @@ -233,12 +247,12 @@ public void onLoginSuccess() { if (VPNService.isUsingAlwaysOnVPN(this)) { showAlwaysOnDialog(() -> { if (mBinder != null) { - mBinder.runEngine(urlOpener, isRunningOnTV); + mBinder.runEngine(urlOpener, useDeviceCodeFlow); } }); } else { if (mBinder != null) { - mBinder.runEngine(urlOpener, isRunningOnTV); + mBinder.runEngine(urlOpener, useDeviceCodeFlow); } } }); @@ -345,7 +359,7 @@ public void switchConnection(boolean status) { if (prepareIntent != null) { vpnActivityResultLauncher.launch(prepareIntent); } else { - mBinder.runEngine(urlOpener, isRunningOnTV); + mBinder.runEngine(urlOpener, useDeviceCodeFlow); } } diff --git a/app/src/main/java/io/netbird/client/PlatformUtils.java b/app/src/main/java/io/netbird/client/PlatformUtils.java index dd0d6f0..3e06081 100644 --- a/app/src/main/java/io/netbird/client/PlatformUtils.java +++ b/app/src/main/java/io/netbird/client/PlatformUtils.java @@ -2,6 +2,7 @@ import android.app.UiModeManager; import android.content.Context; +import android.content.pm.PackageManager; import android.content.res.Configuration; public final class PlatformUtils { @@ -16,5 +17,15 @@ public static boolean isAndroidTV(Context context) { } return false; } + + public static boolean isChromeOS(Context context) { + PackageManager pm = context.getPackageManager(); + return pm.hasSystemFeature("org.chromium.arc") + || pm.hasSystemFeature("org.chromium.arc.device_management"); + } + + public static boolean requiresDeviceCodeFlow(Context context) { + return isAndroidTV(context) || isChromeOS(context); + } } From 92d88235367cef14ca2a005f318e6a52b3e739d3 Mon Sep 17 00:00:00 2001 From: mlsmaycon Date: Mon, 26 Jan 2026 18:21:43 +0100 Subject: [PATCH 2/2] update submodule --- netbird | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbird b/netbird index 245481f..6721101 160000 --- a/netbird +++ b/netbird @@ -1 +1 @@ -Subproject commit 245481f33be5b37a45806d7a56e7190ca38f30e7 +Subproject commit 67211010f7240d53734abd922777c32fccb02754