Cross-browser extension that enables Microsoft Entra ID (Azure AD) SSO on Linux by communicating with the microsoft-identity-broker D-Bus service.
On Linux, Microsoft Entra ID conditional access (Intune device compliance) only works in Microsoft Edge. Firefox, LibreWolf, Chromium, Brave, and Vivaldi cannot authenticate to Entra ID-protected services because they lack integration with the Microsoft Identity Broker.
On Windows and macOS this isn't an issue -- the OS-level identity broker (WAM / Company Portal) works with all browsers. On Linux, the broker exists as a standalone D-Bus service but only Edge knows how to talk to it.
- Native Messaging Host -- Python daemon communicating with
com.microsoft.identity.broker1via D-Bus - Cross-browser WebExtension -- Sets the PRT SSO cookie in the browser's cookie store via
cookies.set()API
| Browser | Support | Notes |
|---|---|---|
| Firefox | Manifest V3 | Full support (signed .xpi) |
| LibreWolf | Manifest V3 | Full support (unsigned extensions allowed by default) |
| Chromium | Manifest V3 | Full support (load unpacked) |
| Brave | Manifest V3 | Full support (load unpacked) |
| Vivaldi | Manifest V3 | Full support (load unpacked) |
| Thunderbird | Manifest V3 | Firefox-based; native host via install.sh, signed .xpi |
| Edge | Not needed | Built-in broker integration |
Works with all Entra ID protected services requiring Conditional Access via login.microsoftonline.com -- Jira, GitHub Enterprise, Office 365, Azure Portal, and any SAML/OAuth-integrated application.
Browser (Firefox / LibreWolf / Chromium / Brave / Vivaldi)
|
+-- Extension sets PRT SSO cookie via cookies.set() API
|
+-- Native Messaging (stdin/stdout)
| |
| +-- Python host calls D-Bus: acquirePrtSsoCookie()
| | |
| | +-- microsoft-identity-broker returns SSO cookie
| |
| +-- Returns cookie to extension
|
+-- Browser automatically includes cookie in requests
|
+-- Entra ID sees compliant device
- Linux with D-Bus session bus (any desktop environment)
- A Secret Service provider (
org.freedesktop.secrets):- GNOME / XFCE: gnome-keyring (usually pre-installed)
- KDE Plasma: KWallet with Secret Service integration
- Sway / i3 / etc: KeePassXC (enable Secret Service in settings)
- microsoft-identity-broker service running:
systemctl --user status microsoft-identity-broker.service
- Device enrolled in Microsoft Intune (Edge SSO must already work)
- Python 3.9+ with
dbus-python
The linux-entra-bridge package installs the native messaging host system-wide and the unpacked extension under /usr/share/linux-entra-bridge/extension (for Chromium/Brave/Vivaldi). Firefox users additionally install the signed .xpi from AMO.
openSUSE Tumbleweed
sudo zypper addrepo https://download.opensuse.org/repositories/home:Pihaar:linux-entra-bridge/openSUSE_Tumbleweed/home:Pihaar:linux-entra-bridge.repo
sudo zypper refresh && sudo zypper install linux-entra-bridgeopenSUSE Leap 15.6
sudo zypper addrepo https://download.opensuse.org/repositories/home:Pihaar:linux-entra-bridge/15.6/home:Pihaar:linux-entra-bridge.repo
sudo zypper refresh && sudo zypper install linux-entra-bridgeFedora 43
sudo dnf config-manager --add-repo https://download.opensuse.org/repositories/home:Pihaar:linux-entra-bridge/Fedora_43/home:Pihaar:linux-entra-bridge.repo
sudo dnf install linux-entra-bridgeRockyLinux 9 (binary-compatible with RHEL 9, which is not on OBS)
sudo dnf config-manager --add-repo https://download.opensuse.org/repositories/home:Pihaar:linux-entra-bridge/RockyLinux_9/home:Pihaar:linux-entra-bridge.repo
sudo dnf install linux-entra-bridgeDebian 13
echo 'deb [signed-by=/etc/apt/keyrings/home_Pihaar_linux-entra-bridge.gpg] https://download.opensuse.org/repositories/home:/Pihaar:/linux-entra-bridge/Debian_13/ /' | sudo tee /etc/apt/sources.list.d/home_Pihaar_linux-entra-bridge.list
curl -fsSL https://download.opensuse.org/repositories/home:/Pihaar:/linux-entra-bridge/Debian_13/Release.key | gpg --dearmor | sudo tee /etc/apt/keyrings/home_Pihaar_linux-entra-bridge.gpg > /dev/null
sudo chmod a+r /etc/apt/keyrings/home_Pihaar_linux-entra-bridge.gpg
sudo apt update && sudo apt install linux-entra-bridgeMore distributions (Leap 16, SLFO/SLE, CentOS Stream, Ubuntu, Arch, and others) are on the OBS project page.
To build from source instead, use the steps below.
git clone https://github.com/Pihaar/linux-entra-bridge.git
cd linux-entra-bridge
bash native-host/install.shThis auto-detects installed browsers and installs the native messaging manifest for each.
Published in the browser stores (easiest for end users):
- Firefox / LibreWolf: Mozilla Add-ons (available once the AMO review completes)
- Chrome / Chromium / Brave / Vivaldi: Chrome Web Store
- Thunderbird: addons.thunderbird.net
The store extension still needs the native messaging host from step 1 (or the RPM package) to reach the broker. Installing only the extension is not enough.
Manual / offline alternatives:
Build and sign the .xpi yourself (no CI/CD -- signing requires AMO API credentials):
export WEB_EXT_API_KEY="your-key"
export WEB_EXT_API_SECRET="your-secret"
make signThe signed .xpi appears in web-ext-artifacts/firefox/. Install it via:
about:addons --> gear icon --> "Install Add-on From File" --> select the .xpi
LibreWolf: Unsigned extensions are allowed by default, so you can also use
make build-firefox(no AMO credentials needed) and install the unsigned.xpi.
make build-chromiumThen load the unpacked extension:
- Open
chrome://extensions(orbrave://extensions,vivaldi://extensions) - Enable Developer mode (toggle top-right)
- Click Load unpacked --> select
web-ext-artifacts/chromium/
The extension gets a stable ID (dffhogipdmkddjnppibgmgpcobdnaffk) via the key field in the manifest, so the native messaging host always connects.
Note: Chromium shows a "Developer mode extensions" banner on startup. This is cosmetic.
The extension and native host do not auto-update. After pulling new changes:
cd linux-entra-bridge
git pullChromium / Brave / Vivaldi:
make build-chromium
# Then go to chrome://extensions and click the reload button on the extensionFirefox / LibreWolf: Re-sign and re-install the .xpi (see above).
Native host: Updates to linux_entra_bridge.py take effect immediately on the next browser restart; the native messaging manifest points directly to the repo clone. Only re-run bash native-host/install.sh if you move the repo directory or the manifest format changes.
Important: Do not move or delete the repo clone, because both the unpacked extension (Chromium) and the native messaging manifests reference files in it by absolute path.
For managed Linux desktops, see contrib/README-enterprise.md for IT admin instructions including Chromium policy templates and RPM packaging.
- Auto dark/light mode following OS/browser preference (WCAG AA contrast)
- Account selection UI with cookie cleanup on switch
- SSO nonce support for Conditional Access (Intune Company Portal)
- SPA Background SSO: opt-in per-origin nonce injection for single-page apps
- Device compliance check via MS Graph (opt-in, informational only; Intune remains authoritative)
- Structured logging with popup log viewer
- Broker v2/v3 API compatibility (cookieItems normalization)
- Broker version change warning
- Chromium service worker health state persistence
- Exponential backoff health circuit breaker
- Force refresh button and badge indicator
- httpOnly PRT cookie, 24h TTL cap, prototype pollution prevention
- 423 tests (280 JS vitest + 143 Python pytest)
linux-entra-bridge/
+-- extension/ # WebExtension (vanilla JS, no bundler)
| +-- background.js # Background script: cookie lifecycle, logging
| +-- popup.html / popup.js # Status popup with log viewer
| +-- options.html / options.js # Settings (debug toggle, broker check)
| +-- theme.css # Shared CSS variables (dark/light mode)
| +-- popup.css / options.css # Component-specific styles
| +-- lib.js # Shared utilities (API shim, truncation)
| +-- *-init.js # MV3 CSP-compliant entry points
| +-- icons/ # Extension icons (SVG + PNG)
+-- manifests/ # Browser-specific manifests
| +-- firefox.json # Firefox/LibreWolf (Manifest V3)
| +-- chromium.json # Chromium/Brave/Vivaldi (Manifest V3)
| +-- thunderbird.json # Thunderbird (Manifest V3)
+-- native-host/ # Native Messaging Host
| +-- linux_entra_bridge.py # D-Bus broker communication (Python)
| +-- install.sh # Auto-detect browsers, install NM manifests
+-- contrib/
| +-- linux-entra-bridge.spec # RPM spec for system-wide install
| +-- chromium-policy.json # Enterprise policy template
| +-- README-enterprise.md # IT admin deployment guide
+-- tests/ # Test suites
| +-- js/ # vitest + jsdom (background, popup, options)
| +-- python/ # pytest (broker, messaging, CLI, integration)
+-- research/ # Reverse-engineering documentation
| +-- broker-schemas/ # JSON schemas from broker JAR
| +-- BROKER-API.md # D-Bus API reference
| +-- capture-broker-calls.sh # dbus-monitor capture script
+-- Makefile # check/install/build/sign/test/rpm
+-- SECURITY.md # Security notes + protocol fragility
+-- CHANGELOG.md
+-- LICENSE # MIT
This extension communicates with the Microsoft Identity Broker using reverse-engineered constants observed via dbus-monitor on Edge's D-Bus calls. These are not part of any public API and may break on broker updates. The extension logs a warning when the broker major version changes. See SECURITY.md for details and research/BROKER-API.md for the full D-Bus API reference.
make check # Verify prerequisites + test native host
make test # Run all 423 tests (JS + Python)
make lint # ESLint + ruff
make coverage # Coverage reports (JS + Python)
make build # Build both Firefox + Chromium
make rpm # Build RPM package
make check-version # Verify version consistency across manifests- microsoft-identity-broker -- Microsoft's Linux identity broker
- MSAL C++ -- Microsoft Authentication Library (what Edge uses)
- WebExtension Native Messaging -- Browser native messaging API
MIT