
June 3, 2026
The official client doesn't exist, openconnect gives you 'No SSO handler', and every openconnect-sso fork is broken. Here's what actually works.
My workplace runs Cisco AnyConnect with Azure AD — every connection goes through a browser-based SAML/MFA flow. Getting that working on NixOS turns out to be surprisingly painful.
The obvious approaches all fail. The official client has no NixOS package. Plain openconnect exits with No SSO handler the moment the server wants SAML. And openconnect-sso, which was built for exactly this, depends on a PyQt5 WebEngine that's been broken in nixpkgs for ages.
The solution uses networkmanager-openconnect and nm-applet, both already in nixpkgs. When vpn-connect runs, it creates a fresh NetworkManager VPN profile and fires nmcli connection up. NetworkManager then asks nm-applet for credentials — nm-applet opens a browser window, handles the Azure AD / SAML redirect, and passes the token back automatically. No patching, no broken Python deps.
The connection profile is created with:
vpn.data "gateway=…,protocol=anyconnect,useragent=AnyConnect"
useragent=AnyConnect is the critical bit. Without it the server sees a generic OpenConnect string and falls back to username/password — the SAML redirect never fires.
Before creating the profile, the script deletes any existing one with the same name. NetworkManager caches the auth cookie, and when it expires the connection silently fails instead of re-authenticating — a fresh profile forces a new SSO flow every time.
nm-applet is started on demand inside the connect script (nm-applet --indicator &) if it isn't already running, so no autostart entry or systemd user service is needed.
I wrapped this into a NixOS flake module: nixos-anyconnect-webauth
services.anyconnect-webauth = {
enable = true;
connections.work.gateway = "vpn.company.com";
};Then vpn-connect work opens the browser for MFA and brings the tunnel up. vpn-disconnect work tears it down.