Skip to content

Zero trust · guide

Signing in through an identity provider (OIDC and tokens)

8 min read · Last checked 10 October 2026

This page explains how a person signs in to an OpenZiti network with a work account, as Module 5 of the course sets it up. You don’t need to write code to follow it. It uses public and private keys, which the certificates guide explains. To sign data, a program uses a private key to make a value from it, called a signature, which anyone with the matching public key can check.

  • The OpenZiti controller is the program that manages the network and keeps the rules about who may reach what.
  • In OpenZiti, an identity is the record for one person or device. An attribute is a tag on it, such as #remote-users, that policies use to decide what it can reach.
  • A tunneler is the OpenZiti app that connects a person’s computer to the network. The course uses Ziti Desktop Edge for Windows, the one for Windows computers.

An identity provider is a service that keeps a list of user accounts and checks sign-ins for other apps, so each app doesn’t have to store its own passwords.

The course uses Microsoft Entra ID, Microsoft’s cloud service for user accounts and sign-in. Each organization has its own space in it, a tenant, named by a long code, the tenant ID.

The controller could check sign-ins itself. Module 5 uses Entra ID so the company keeps its existing accounts and sign-in checks, and someone removed there loses the network too.

Authentication (sign-in) proves who you are. Authorization (permission) decides what you may do. Entra ID handles the first, and OpenZiti’s own policies handle the second.

OpenID Connect (OIDC) is an open standard for handing sign-in to an identity provider, which OIDC calls an OpenID provider. Each app is first registered with the provider. In Entra ID that record is an app registration (the course’s is openziti-meridian), and it gets a client ID, which is the app’s ID in Entra ID.

A sign-in goes like this:

  1. You open the app, and it sends your browser to the provider’s sign-in page.
  2. You sign in there, with your password and any extra checks the provider asks for.
  3. The provider sends your browser back to the app, and the app then collects a token: a piece of text that states who you are, signed with the provider’s private key.
  4. The app checks the signature with the provider’s public key, which the provider publishes at a fixed web address. OpenZiti calls that address the JWKS endpoint.

The app never sees your password.

The token is a JSON Web Token (JWT). JSON is a common text format for data. A JWT carries claims, which are pieces of information about the person, each written as a name and a value. It has three parts, separated by full stops: a header that says how it was signed, a payload that holds the claims, and the signature, which shows that the provider made the token and nobody has changed it.

OpenZiti uses Entra ID’s access token, the kind made for one particular app. That’s the token on this page.

  • oid: the user’s object ID. It’s a long code that never changes, and it’s the same for every app in the tenant.
  • roles: the roles assigned to the user in this app. An administrator creates a role in the app registration and gives it a value, the short text the token carries. In the course, a role called Logistics has the value remote-users. Alex holds that role, so Alex’s token lists remote-users.
  • preferred_username: the user’s sign-in name. Microsoft says it can change, so it shouldn’t decide permissions.

That’s why the course matches people on oid.

  • The issuer (iss) names the provider that made the token. In the course it looks like https://login.microsoftonline.com/<tenant-id>/v2.0.
  • The audience (aud) names the app the token is for. An app that isn’t the audience must reject the token. In the course, the audience is the client ID.

Entra ID has two versions of access token, and the issuer and audience look different in each. Module 5 sets requestedAccessTokenVersion to 2 in the app registration’s settings file, called the manifest. That’s why the issuer ends in /v2.0 and the audience is the client ID.

Every token carries an expiry time (exp), after which it must be refused. That limits how long a stolen token works. It also limits how long someone keeps access after their account is turned off. By default, Entra access tokens last 60 to 90 minutes, chosen at random, and OpenZiti’s own last 30.

Multifactor authentication (MFA) asks for two or more kinds of proof: something you know (a password), something you have (a phone or a hardware key), or something you are (a fingerprint or a face).

A common second factor is a TOTP code (time-based one-time password). You set it up by scanning a QR code into an authenticator app. The QR code holds a shared secret, a value both your phone and the server keep. The app turns that secret and the current time into a short code, which changes every 30 seconds by default.

In the course, Entra ID may ask for its own MFA through the Microsoft Authenticator app. OpenZiti’s TOTP code is a separate step.

The controller needs two objects:

  • An external JWT signer tells the controller to trust tokens from one provider. It records the issuer, audience, JWKS endpoint, and the claim that names the person (oid). After checking the token, the controller looks for the identity whose external ID matches that claim. The course’s signer is meridian-entra.
  • An authentication policy decides which kinds of sign-in an identity may use, and whether a second factor is required. The course’s meridian-entra-policy allows sign-in through meridian-entra and requires a TOTP code. Changes to a policy apply to new sign-ins only.

The identity can come about in two ways. You can create Alex’s identity yourself, with Alex’s object ID as its external ID and the #remote-users attribute. Or the signer creates it automatically at Alex’s first sign-in, taking the name from preferred_username and the attribute from the roles claim.

Put together: Alex signs in from Ziti Desktop Edge and enters the TOTP code. The controller matches the token’s oid to the external ID of the identity alex@meridian.com. That identity carries the #remote-users attribute, so the existing meridian-yard-dial policy lets Alex reach the yard app.

One sign-in with Entra ID1: Ziti Desktop Edge, the tunneler on Alex’s computer, sends Alex to Entra ID’s sign-in page. 2: Alex signs in there with a password and any extra checks. 3: Entra ID sends Alex back with a token. 4: the token goes to the OpenZiti controller, and the controller checks it: its signature with the public keys Entra ID publishes at the JWKS endpoint, checks the issuer, audience and expiry, and matches the oid claim to an identity. 5: Alex enters a TOTP code, which the authentication policy requires. 6: the identity’s #remote-users attribute and the meridian-yard-dial policy let Alex reach the yard app. ENTRA IDidentity provider2Alex signs in:password, extra checksZITI DESKTOP EDGEthe tunneler on Alex’s computerCONTROLLEROpenZiti1sign-in page3back, witha tokenpublic keys, at theJWKS endpoint4the token; the controller checks it5a TOTP code: theauth policy requires itchecks signature, issuer,audience and expiry;matches oid to an identity6#remote-users andmeridian-yard-diallet Alex inYARD APPreached over OpenZiti
One sign-in: steps 1 to 4 follow the list above, and in step 4 it's the controller that checks the token. Then the TOTP code, and the policy that lets Alex in.

These run in PowerShell on your workstation, after the command line has signed in to the controller. Values in <…> come from your own Entra tenant.

Command What it does
ziti edge create ext-jwt-signer meridian-entra <issuer> --external-auth-url <issuer> --jwks-endpoint <jwks-url> --audience <client-id> --client-id <client-id> --claims-property oid --scopes openid,profile,offline_access,api://<client-id>/auth --target-token ACCESS --enroll-to-token --enroll-name-claims-selector preferred_username --enroll-attr-claims-selector roles Tells the controller to trust Entra ID’s tokens. --jwks-endpoint is where Entra ID publishes its public keys. --claims-property oid picks the claim that names the person. --scopes lists what the sign-in asks Entra ID for, separated by commas. --target-token ACCESS uses the access token. The --enroll-… flags turn on automatic identity creation, with the name from preferred_username and attributes from roles.
ziti edge list ext-jwt-signers Lists the providers the controller trusts.
ziti edge update ext-jwt-signer <name> --claims-property <claim> Changes which claim in the token names the person.
ziti edge create auth-policy <name> --primary-ext-jwt-allowed --primary-ext-jwt-allowed-signers <signer> --secondary-req-totp Creates a policy that accepts sign-in through that provider and requires a TOTP code.
ziti edge update ext-jwt-signer <name> --enroll-auth-policy <policy> Puts identities created at first sign-in on that policy instead of the default one.
ziti edge list auth-policies Lists the authentication policies and what each one allows.
ziti edge update auth-policy <name> --secondary-req-totp=false Switches one policy setting off. Keep the = sign, because without it the setting stays on.
ziti edge create identity <name> --external-id <object-id> -a <attribute> Creates an identity that a token’s oid will match, with an attribute that policies can target.
ziti edge list identities Lists identities, including the ones created at first sign-in.
ziti edge login <controller-address>:1280 -e <jwt-file> Signs the command line in with a token. 1280 is the controller’s port in the course: the number that tells the machine which program a connection is for. The command line can’t open a browser to sign in, so the file holds a token you already got from Entra ID, which is useful for scripted checks.

Sources

Facts on this page are explained in our own words. Short quotes are marked and linked.