Microsoft sign-in for Directus follows the same shape as Google, with three differences that will cost you an afternoon if nobody mentions them: the issuer URL is not the one most tutorials copy, the platform type in the app registration matters, and group-to-role mapping actually works here — unlike Google, where it quietly cannot.

Examples use https://cms.contensu.com as the Directus address. Swap in your own.

There is no Microsoft driver either

As with Google, Directus has no provider-specific driver. Microsoft Entra ID — the service that used to be called Azure Active Directory — publishes an OpenID Connect discovery document, so you use the openid driver and point it at Microsoft. One URL, and Directus finds the rest.

Step 1 — Register the application

Open the Entra admin centre and go to Applications → App registrations → New registration.

Two choices matter here.

  • Supported account types. Pick Accounts in this organizational directory only if only your own staff should sign in. This is the usual answer for a CMS, and it also gives you the simpler issuer URL below. Choose a multi-tenant option only if you genuinely want other organisations signing in.
  • Redirect URI. Choose the Web platform — not Single-page application. SPA expects a browser-side flow with different rules; picking it produces a failure much later that says nothing about platform types. Then enter exactly:
https://cms.contensu.com/auth/login/microsoft/callback

The shape is always [PUBLIC_URL]/auth/login/[provider name]/callback, and Directus builds it from PUBLIC_URL rather than from the address in your browser — so if PUBLIC_URL is wrong, Microsoft rejects the redirect no matter how right the URL bar looks.

Step 2 — Collect three values

From the app registration's Overview panel:

  • Application (client) ID — a UUID. This is your client ID.
  • Directory (tenant) ID — a different UUID. This goes in the issuer URL.

Then Certificates & secrets → New client secret. Copy the Value, not the Secret ID — they sit next to each other and the Value is only shown once. If you navigate away before copying it, you cannot retrieve it and must create another.

Label both UUIDs as you copy them. Client ID and tenant ID look identical and swapping them gives an error that does not tell you which one is wrong.

Step 3 — The issuer URL, and why most tutorials get it wrong

Use your tenant ID:

https://login.microsoftonline.com/YOUR-TENANT-ID/v2.0/.well-known/openid-configuration

Plenty of guides tell you to use common instead. Fetch that document and you will see the problem:

"issuer": "https://login.microsoftonline.com/{tenantid}/v2.0"

The issuer is templated — it contains a literal placeholder rather than a real value. The token Microsoft later issues carries a concrete issuer with your actual tenant in it, and a strict OpenID client can refuse the mismatch. Using your tenant ID makes the discovered issuer and the token issuer identical, which is one fewer thing that can fail. It also means only your organisation can sign in, which is usually what you wanted.

Step 4 — Configure Directus

AUTH_PROVIDERS="microsoft"

AUTH_MICROSOFT_DRIVER="openid" AUTH_MICROSOFT_ISSUER_URL="https://login.microsoftonline.com/YOUR-TENANT-ID/v2.0/.well-known/openid-configuration" AUTH_MICROSOFT_CLIENT_ID="your-application-client-id" AUTH_MICROSOFT_CLIENT_SECRET="the-secret-VALUE-not-the-id" AUTH_MICROSOFT_IDENTIFIER_KEY="sub" AUTH_MICROSOFT_ALLOW_PUBLIC_REGISTRATION="true" AUTH_MICROSOFT_DEFAULT_ROLE_ID="paste-a-role-uuid-here" AUTH_MICROSOFT_LABEL="Microsoft" AUTH_MICROSOFT_ICON="microsoft"

Restart Directus, open /admin/login, and a Microsoft button appears beneath the email and password form.

Step 5 — Group mapping, which actually works here

This is the real advantage over Google. Google's discovery document offers no groups claim at all, so role mapping cannot work no matter how it is configured. Entra can send one — it just does not by default.

In your app registration, open Token configuration → Add groups claim and choose which groups to include. Then:

AUTH_MICROSOFT_GROUP_CLAIM_NAME="groups"
AUTH_MICROSOFT_ROLE_MAPPING="{\"group-object-id\":\"directus-role-uuid\"}"

Two things to know. Entra sends group object IDs, not display names, so the keys are UUIDs — copy them from the group's overview page. And Directus stops at the first matching group, so if someone belongs to several mapped groups, the order of your mapping decides their role.

If the claim is missing or empty, Directus logs a debug line saying so and falls back to the default role. That log line is the quickest way to tell whether the claim is arriving at all.

Trying it on localhost first

Entra allows http://localhost as a redirect URI — its one exemption from the HTTPS rule — so this can be proved on your laptop before it goes anywhere near a real domain.

Register the loopback URI under Web

Add http://localhost:8055/auth/login/microsoft/callback to the same app registration, on the Web platform — for the same reason as the production URI, and it is worth repeating because the consequence surfaces late and mentions nothing about platforms. One registration holds several redirect URIs, so production and localhost coexist happily. The port is part of the string.

Make Directus send that URI

Directus derives the callback from PUBLIC_URL, not from the address in your browser. A local instance still announcing the production PUBLIC_URL sends Microsoft the production callback, and Entra rejects it as a mismatch while everything on your screen looks right. Either set PUBLIC_URL=http://localhost:8055 locally, or — on Directus 11.14.1 and later — keep it and add AUTH_ALLOWED_PUBLIC_URLS=http://localhost:8055, which lets one instance serve several origins: Directus matches the request protocol and host against that list and falls back to PUBLIC_URL. The match is exact, port included.

The defaults are already right for HTTP — SESSION_COOKIE_SECURE is false and same-site is lax. Copying a production .env brings SESSION_COOKIE_SECURE=true and possibly AUTH_MICROSOFT_COOKIE_SECURE="true" with it, and a secure cookie over plain HTTP is discarded by the browser without comment. Microsoft authenticates you, Directus sets a session you never receive, and you land back on the login screen with nothing in the log to explain it.

If Directus runs in Docker, PUBLIC_URL must be the address the browser uses. Microsoft redirects the browser, which cannot resolve http://directus:8055 on the Compose network.

The steps people forget

Copying the Secret ID instead of the secret Value

They are adjacent in the table and both look like opaque identifiers. Only the Value works, and only the Value disappears when you leave the page.

Choosing the SPA platform for the redirect URI

Directus is a confidential client using a server-side code exchange. Register the URI under Web. The failure from picking SPA arrives later and mentions nothing about platforms.

Using common and hitting issuer validation

Covered above. Use your tenant ID.

Unknown users being rejected

Public registration is off by default, so a colleague who has never signed in has no Directus user and is refused with an invalid credentials error — even though Microsoft authenticated them perfectly. Turn on AUTH_MICROSOFT_ALLOW_PUBLIC_REGISTRATION and set a default role, or create their user first with the External Identifier set to their sub.

Expecting names to appear

Entra's standard claims include sub, name, preferred_username, email and tid — but not necessarily given_name and family_name, which is what Directus reads for first and last name. Users can arrive with an empty name field. Add the optional claims in Token configuration if you want them populated.

The client secret expiring

Entra secrets have a maximum lifetime of two years, and the default offered is shorter. SSO will simply stop working on that date, months after anyone remembers configuring it. Put the expiry in a calendar the day you create it.

The licence tier, but only on Directus 12

This one depends on your version, and it is worth getting right. Directus 11 has no licence module at all — SSO is ungated, and everything in this guide works on a stock 11.17.4. Licensing arrived in 12.0.0, and there the SSO routes sit behind an sso_enabled entitlement: without it the login and callback routes return 404 rather than failing loudly, and Directus logs a warning at startup — you have SSO providers configured these will be unavailable under the current license tier. So if you are on 12 and the provider is simply absent, check the entitlement before you start doubting your configuration.

What about GitHub, Okta, Auth0 and the rest?

Anything that publishes an OpenID discovery document — Okta, Auth0, Keycloak, most corporate identity providers — works exactly like this. Change the issuer URL, the client ID and the secret, and you are done.

GitHub is the exception. It does not publish an OpenID discovery document for user sign-in, so the openid driver cannot be used at all. GitHub needs the oauth2 driver, where you supply the authorise, token and profile URLs yourself, along with which field in the profile response is the identifier and which is the email. That is a different enough setup to deserve its own guide.

We build on Directus daily and publish the extensions we needed along the way — all free and MIT-licensed, on our tools page.

Common questions

Which Directus driver do I use for Microsoft sign-in?

The openid driver. Microsoft Entra ID — the service formerly called Azure Active Directory — publishes an OpenID Connect discovery document, so Directus can find the authorisation, token and userinfo endpoints from a single URL. There is no Microsoft-specific driver.

What is the difference between the common and tenant-specific issuer URL?

The common endpoint accepts accounts from any Microsoft tenant, and its discovery document reports a templated issuer — the tenant id appears as a placeholder in braces rather than a real value. Some OpenID clients reject that because the issuer they receive in the token does not match the one they discovered. Using your own tenant ID in the URL gives a concrete issuer and avoids the problem entirely, and it is what you want anyway if only your organisation should sign in.

Where do I find my Microsoft tenant ID?

In the Entra admin centre, open your app registration and read the Directory (tenant) ID from the Overview panel. It is a UUID. The same panel shows the Application (client) ID, which is a different UUID — copy both and label them, because mixing them up produces an error that does not say which one is wrong.

Can I map Microsoft groups to Directus roles?

Yes, and this is where Entra beats Google. Groups are not in the token by default — you add a groups claim under Token configuration in your app registration. Once the claim is present, set AUTH_MICROSOFT_GROUP_CLAIM_NAME to groups and AUTH_MICROSOFT_ROLE_MAPPING to a JSON object mapping group to Directus role ID. Note that Entra sends group object IDs, not names, so the keys in your mapping are UUIDs.

Why does sign-in work for me but fail for colleagues?

Usually the app registration's supported account types. If it is set to accounts in this organisational directory only, external accounts are refused by Microsoft before Directus sees anything. The other common cause is that Directus rejects unknown users: public registration is off by default, so a colleague with no existing Directus user is turned away with an invalid credentials error.

What redirect URI does Microsoft need?

Your Directus public URL followed by /auth/login/ then your provider name then /callback. With PUBLIC_URL set to https://cms.contensu.com and a provider named microsoft, that is https://cms.contensu.com/auth/login/microsoft/callback. Register it under the Web platform, not Single-page application — the SPA platform expects a different flow and fails later with an unhelpful message.

Can I test Microsoft SSO on localhost?

Yes. Entra allows http://localhost as a redirect URI, which is its only exemption from the HTTPS requirement. Register http://localhost:8055/auth/login/microsoft/callback on the Web platform of the same app registration, point PUBLIC_URL at localhost or list it in AUTH_ALLOWED_PUBLIC_URLS, and leave SESSION_COOKIE_SECURE false while you are on plain HTTP.

Entra sign-in still refusing your colleagues?

Half of Directus SSO work is not the provider at all — it is deciding who gets a user, which Entra group becomes which Directus role, and what a first-time sign-in is allowed to see. We do that on Directus for a living. Fifteen minutes on a call and you will know whether this is a configuration problem or a permissions one.

Book a 15-minute call

More articles

Directus8 August 202612 min read

How to Set Up Google SSO Login in Directus (Step by Step)

Directus8 August 202613 min read

How to set up LDAP and Active Directory login in Directus

Directus8 August 202612 min read

How to set up GitHub SSO login in Directus

Back to all articlesBack to top