Sign In with Microsoft Entra ID
If your organization manages its people in Microsoft Entra ID, Semantius can use it directly. Who has access, how they authenticate (multi-factor authentication, conditional access) and when access ends are then managed in Entra, in one place, instead of in a separate user list that someone has to keep in sync. When someone leaves and is removed in Entra, they lose access to Semantius at the same moment.
The repository ships a ready-made variant for exactly this, local-entra-idp: the same stack, set up for Entra ID to handle sign-in. After setup, follow Running Your Stack and Going Live as usual; both pages point out where this variant differs.
This is a different folder rather than a setting, because the built-in sign-in system is genuinely absent from it. Running both at once would give you two competing sign-in systems on one address.
What You Need
- Docker, as with any variant.
- An Entra tenant, and someone allowed to register applications in it. That is the Application Developer role or higher, and it may well be someone else in your organization rather than you.
- For the setup script only: PowerShell 7 and the Azure CLI. Everything it does can also be done by hand in the Entra admin center.
Entra support needs recent images. When you pin versions, as Going Live recommends for a server, pin versions you have tested sign-in with, and do not pin older than that. An image that predates Entra support shows up as a confusing error at sign-in, 90002, rather than as a clear version complaint.
1. Get the Files
git clone https://github.com/semantius/semantius-self-hostedcd semantius-self-hosted/variants/local-entra-idp./setup-env.shThat creates .env with database passwords generated. Everything else gets filled in by the next step.
Unlike the other variants, this one will not start until it is configured. That is on purpose: a stack with no working sign-in would boot into a broken state and look like a bug, so instead it stops and names the setting it is missing.
2. Register Three Applications in Entra
Semantius needs three registrations in your tenant: one for the API (what access is granted to), one for the web app (what people sign in to), and one for the semantius CLI that coding agents use.
With the Script
If you have rights in the tenant, the repository includes a PowerShell script that does the whole thing:
az login --tenant yourcompany.onmicrosoft.com --allow-no-subscriptions
./setup-entra.ps1
The --allow-no-subscriptions flag matters. A Microsoft 365 tenant usually has no Azure subscription attached, and without the flag the login ends with “No subscriptions found” and leaves you signed out. App registrations do not need a subscription.
The script asks for your front door address, creates all three registrations, pre-approves them so nobody sees a consent prompt, assigns you access, turns on the gate that requires assignment, and writes every resulting value into .env.
Re-running it is safe. It looks each registration up first and refuses to overwrite an .env that is already configured. Run it again on a configured stack and it prints what you have instead: the three application ids, who holds access, whether the gate is on, and a direct link to every page in the Entra admin center that owns one of those values. Add -Verify and it checks each one and exits with an error code if something is wrong, which makes it usable in a pipeline. Both of those modes only read, so they are safe to run against a stack people are using.
Without Rights in the Tenant
If someone else administers Entra, they can run the script with -NoWrite. It creates the registrations and prints the values instead of writing them, so they can send you the results to paste into .env without giving you access to the tenant.
Doing it entirely by hand in the Entra admin center is also fully documented, in the variant’s own README. There are a few settings in there that are easy to get subtly wrong, so the script is worth using when you can.
Running More Than One Semantius
A CRM and an HR system, or production and test, each get their own set of registrations:
./setup-entra.ps1 -NamePrefix "Semantius CRM"
./setup-entra.ps1 -NamePrefix "Semantius HRM"
Each prefix gets its own access list and its own separate permission, so access to one does not grant access to the other. Note that a person ends up with a different internal identity on each one, which means user records do not carry across if you copy data between them.
If you set up a second stack with the same prefix, it silently joins the first: one access list, and logins valid on both. The script refuses to do that by accident.
3. Give People Access
In the Entra admin center, go to Enterprise applications, then Semantius API, then Users and groups, and assign people to the authenticated role.
This is the real gate. Because the script turns on Assignment required, somebody without that role is refused by Microsoft at the sign-in page and never reaches Semantius at all. Someone who somehow arrives without it lands with no permissions and can read nothing.
Two practical notes:
- Assigning groups requires an Entra ID P1 license. Assigning individual users works on the free tier.
- A newly assigned person’s first sign-in can still fail. The assignment takes about a minute to reach Microsoft’s token service. Wait and try again before assuming something is broken.
4. Start It
./create.shThen open your front door address, http://localhost:3000 by default, and sign in with your work account.
On an empty database, the first person to sign in becomes the administrator. Everyone after that arrives with the default role and sees nothing until an administrator grants them access, under Administration, then Users.
That is worth understanding clearly, because there are now two separate layers. Entra decides who may sign in. Semantius decides what they can see once they have. Assigning somebody in Entra lets them through the door. It does not give them data.
When Sign-In Goes Wrong
Entra reports failures as codes, which are precise but not self-explanatory. The common ones:
| What you see | What it means |
|---|---|
AADSTS50105 | The person is not assigned to the authenticated role. This is the intended refusal. Assign them under Users and groups. |
AADSTS50011 | The address registered in Entra does not match the one people actually open. It is matched exactly, including the port. |
AADSTS9002326 | The web app was registered as the wrong platform type. It has to be Single-page application. |
AADSTS9010010 | Two settings in .env name different APIs. They have to point at the same one. |
| Everything refused, no role in the token | Either the assignment was made less than a minute ago, or the assignment gate is off and the person was never assigned. |
90002 JWT role claim must be authenticated | The database image predates Entra support. Remove the version pin, or pin a newer release. |
90005 JWT audience does not match | The audience recorded in the database is not the one the token carries. |
The variant’s README carries the full list along with what fixes each one.
Scripts and API Keys
Scripts and scheduled jobs sign in the Entra way, with an access token for the Semantius API registration, sent as a bearer token to /rest/. Personal API keys for scripts come from semantius-idp’s built-in gateway, which this variant does not run. If you need them, add an API gateway such as Kong, Tyk or AWS API Gateway in front of /rest/.
Keeping Keys Fresh
Microsoft periodically replaces the keys used to sign logins, and this variant downloads them once when it starts. A stale copy eventually rejects everybody.
./jwks-refresh.shOn Windows, run jwks-refresh.cmd. It fetches the current keys and restarts the API, which takes about a second, and nobody is signed out. Because Microsoft rotates on its own schedule rather than yours, a daily scheduled run is the safe default here, which is a real difference from the built-in sign-in system where running it on demand is usually enough.
Using a Different Provider
Okta, Keycloak, Auth0 and other OpenID Connect providers that issue JWT access tokens work too, often more easily than Entra. What a provider has to do, and how to run this variant against one or generate a variant of its own, is on Choose or Build Your Variant.
Next Steps
- Running Your Stack: everyday commands and the API.
- Going Live: putting it on a server with your own domain.
- Settings Reference: the settings this variant adds and the defaults it changes.