Hi everyone,
I’m stuck in a loop trying to set up Ziti Desktop Edge for Windows (ZDEW) with Microsoft Entra ID (Azure AD) using an External JWT Signer and the Network JWT method.
Summary / Paradox
-
During login (ZDEW Authorize): controller rejects auth with
identity not found by externalId. -
During manual creation: if I try to create the identity with that externalId, the controller rejects it as a duplicate (so it already exists).
So it looks like the identity exists in the DB, but the external JWT auth path can’t find it.
Evidence
A) Controller log during ZDEW login
After successful Microsoft login, controller logs:
authMethod="ext-jwt" msg="identity not found by externalId" claim_id="user@company.tld"
authMethod="ext-jwt" msg="failed to validate candidate JWT at index 0" error="INVALID_AUTH: The authentication request failed"
B) CLI says the externalId already exists
When trying to create the identity manually:
ziti edge create identity user "user-azure" --external-id "user@company.tld" ...
I get something like:
duplicate value 'user@company.tld' in unique index on identities store
Environment / Setup Notes
-
ZDEW external provider flow uses the Network JWT (my Network JWT payload shows
em: "red"→ not an OTT token). -
Controller + ZAC are running in Docker.
-
I’m aware of the Docker advertised address issue (clients must reach the advertised controller hostname). ZDEW is configured to reach the controller at
<controller-fqdn-or-ip>:1280.
External JWT Signer
issuer: https://login.microsoftonline.com/<tenant-id>/v2.0
jwksEndpoint: https://login.microsoftonline.com/<tenant-id>/discovery/v2.0/keys
clientId: <client-id-guid>
audience: <client-id-guid>
claimsProperty: email
useExternalId: true
targetToken: ID
scopes: [ api://<client-id-guid>/openziti, email, offline_access, openid, profile ]
Token
Decoded ID token contains:
-
iss=https://login.microsoftonline.com/<tenant-id>/v2.0(matches signer) -
aud=<client-id-guid>(matches signer) (Please confirm if Ziti strips 'api://' or requires exact string match) -
email=user@company.tld(matches the identity externalId)
Questions
-
In OpenZiti, can
INVALID_AUTHbe thrown for another reason (issuer/aud/signature) but still surface as “identity not found by externalId”? Or is that message strictly from the identity lookup step? -
Could this happen if ZDEW is authenticating against a different controller instance/advertised address than the one where the identity exists (so CLI shows the identity in one DB but ZDEW hits another)?
-
Is there a recommended way to confirm which externalId the controller actually tries to map (e.g., log level / specific debug flags)?
Any pointers to break this loop would be appreciated. I can share additional sanitized logs (including timestamps and src.remote) if needed.
Thanks!