Seamless SSO authentication with Microsoft Entra ID

Authors: Borislav Shopov, Bogomil Valev

Summary

io.Connect Desktop can sign users into Microsoft Entra ID (formerly Azure AD) applications without a password prompt. On each request to a configured Microsoft login URL, it asks Windows for the proof-of-possession credential the signed-in user already holds, and attaches it to the request.

Key concept: io.Connect Desktop manages no password and caches no token of its own - it borrows the login session Windows has already established. Because the credential is fetched per request rather than stored, no credential on the io.Connect side can go stale. If silent sign-in stops, the state that changed is in Windows, in your tenant policy, or in the Entra session cookies held in the browser profile.

Prerequisites

Access/tools

  • Access to the system.json that io.Connect Desktop actually loads (this may be the local file, a configuration served by io.Manager, or both - a local configuration-overrides file takes precedence over everything else).
  • A non-elevated Command Prompt (to run dsregcmd /status).
  • Access to application.log.

Environment

  • Products: io.Connect Desktop 9.12+ (9.x line), 10.0.4+ (10.x line).
  • OS: Windows only - Seamless SSO is not supported on macOS or Linux; the injection is skipped entirely there.
  • Device: Entra joined, hybrid joined, or Entra registered, with the user signed in to Windows using organizational credentials.

Instructions

Step 1: Enable Entra SSO in the configuration

The entraSSO block is not present in the shipped file and enabled defaults to false, so nothing happens until you add it, in config/system.json:

{
    "entraSSO": {
        "enabled": true,
        "urls": [
            "https://login.microsoftonline.com/*",
            "https://login.microsoft.com/*",
            "https://login.live.com/*",
            "https://*.microsoftonline.com/*"
        ]
    }
}

These four URLs are also the built-in default, so omitting urls gives exactly this list. "urls": [] is not the same as omitting the key: an empty array is honoured as written, nothing matches, and the feature is silently off.

Expected result: io.Connect is ready to attempt automatic login for these addresses.

Step 2: Write your own login endpoint (if needed)

Each entry is compiled as a match pattern. These forms are rejected:

Entry Why
https://login.microsoftonline.com No path component — add /* (a bare trailing / also passes).
https://sts.contoso.com:443/* A host can’t carry a port.
https://*contoso.com/* A wildcard is accepted only as a leading *. label.
login.microsoftonline.com/* No scheme — use https://, or *:// for http and https.

Write federation/custom endpoints as https://host/*, restart, and confirm applications still load before rolling the change out. On the 10.x line, a rejected entry breaks startup rather than degrading quietly (see Troubleshooting).

Step 3: Confirm the setting is live

Checking the file you edited is not the same as checking what the platform loaded. In application.log, search for:

full system config is

This entry carries the whole assembled configuration for the session, written on every start at the default logging level. Confirm entraSSO appears with "enabled": true.

Then verify end to end on a fresh browser profile: launch io.Connect Desktop, check that Entra applications sign in without a prompt and that every application loads. Restart several times over 48 hours, including once after four hours of idle, so a PRT refresh falls inside the window. Note: the browser profile is keyed to the io.Connect Desktop version, not to your application’s version.

Step 4: Check what Windows is holding

As the affected user, in a normal (non-elevated) Command Prompt, while the machine is in the failing state:

dsregcmd /status

Read the SSO State section:

  • AzureAdPrt : YES with a recent AzureAdPrtUpdateTime (normally refreshed roughly every four hours) — Windows is holding what io.Connect asks for; the cause is elsewhere.
  • AzureAdPrt : NO, or an old AzureAdPrtUpdateTime — Windows is not. Sign out/in to Windows, or escalate to your identity team (common causes: device disabled in Entra, TPM problem, federated tenant without WS-Trust, recent password change, connectivity to identity endpoints).

Expected result: confirms whether the issue is inside io.Connect or external.

Step 5: Ask your identity team about sign-in frequency

If the token is healthy and prompts still recur on a cadence, ask whether a Conditional Access sign-in frequency policy covers these applications, and whether the device is registered/enabled in the tenant. Conditional Access isn’t evaluated when the Windows token is issued or renewed, so a healthy token and a forced re-authentication can coexist — this is what a weekly/monthly prompt usually turns out to be.

Step 6: Check whether an application is clearing cookies

Applications configured with allowCookiesManipulation write to the shared session. These writes are logged at the default level, with the requesting application named:

setting cookie {...} requested by <app>
removing cookie name "..." and url "..." requested by <app>

If either appears around the time sign-in starts failing, investigate that application before the tenant.

Troubleshooting

  • Problem: Nothing in the logs explains a failed sign-in.
    Cause: The injection path is close to silent — nothing is logged on success, and nothing is logged when Windows simply returns no credential (the most common failure). failed to inject PRT cookies exists on 10.x only, fires only when the call into Windows fails outright (not the same as a decline), and isn’t emitted on 9.13. Raising the log level adds nothing — there are no debug/trace entries in this path; dsregcmd /status is what actually establishes Windows-side health.
  • Problem: You’re tempted to clear cache/logs before investigating.
    Fix: Capture dsregcmd /status first. Clearing forces a fresh interactive sign-in and appears to “fix” the problem regardless of the real cause, destroying the evidence. If clearing anyway: cookies/local storage live in the cache folder (clearing signs the user out of everything, not just Entra); logs live under the user data folder — copy logs out first.
  • Problem: io.Connect Desktop stops starting after editing urls.
    Cause: On 10.x, a single rejected pattern stops the whole list from building, breaking requests in the app’s main session, surfacing only as a generic unhandled rejection (Invalid match pattern "...": Incorrect format). On 9.13, the bad entry is instead skipped and logged as Invalid Entra SSO URL pattern, and the rest keep working. On both lines, a , ftp://, or urn:// entry compiles cleanly but throws Not implemented: <scheme>:// pattern matching on first match (known issue, raised with engineering).

References

Applies to: io.Connect Desktop 9.12+ (9.x line), 10.0.4+ (10.x line). Windows only.