← Back to list

Building a Multi-Tenant Login in ASP.NET Core with Microsoft Entra ID

A small walk-through of standing up a real multi-tenant login — where any company’s users can sign in — using ASP.NET Core and Microsoft…

Sai Nitesh Palamakula · 2026-06-21 15:12 · 1 claps · 4.1 min read
#azure #authentication #software-engineering #oauth #technology
Open on Medium ↗
Wiki topics: ☁️ · DevOps & Cloud

Building a Multi-Tenant Login in ASP.NET Core with Microsoft Entra ID

A small walk-through of standing up a real multi-tenant login — where any company’s users can sign in — using ASP.NET Core and Microsoft Entra ID. No magic, just an app registration and a few lines of config.

I wanted to build the sign-in experience for a SaaS app the way real products do it: a customer’s company signs up, and their employees log in with the work accounts they already have.

The tool that makes this possible is Microsoft Entra ID (formerly Azure AD) — Microsoft’s cloud identity service. It’s the same system that backs Microsoft 365, so most companies already have a directory of users in it. Each company’s directory is called a tenant. If my app accepts sign-ins from any tenant, any company can use it without me managing a single user account — that’s “multi-tenant” in one line.

The plan: register one app, let users from any tenant sign in, and watch their identity land in my app. Here’s how it went.

Step 1 : Get the mental model right

You register your app once in your own tenant, and that single registration can be used by many other tenants. Think of the registration as a blueprint — when someone from another company signs in for the first time, Entra stamps out a local copy of it (a service principal) inside their directory. Your tenant owns the definition; every customer tenant gets its own runtime instance.

Two settings control this, and they have to agree on both ends:

· In the portal — the registration’s audience is set to Multiple Entra ID tenants (signInAudience: AzureADMultipleOrgs). That’s what permits service principals to be created in foreign tenants.

· In the app — the OIDC authority has to point at the multi-tenant endpoint, not your specific tenant. That’s the AzureAd block in appsettings.json:

Microsoft.Identity.Web stitches Instance + TenantId into the authority it hands to the OpenID Connect handler — here https://login.microsoftonline.com/organizations. That /organizations segment is the whole trick: instead of routing logins through your tenant’s login URL, it routes them through the shared endpoint that accepts work accounts from any organization. (Swap it for a tenant GUID and the same app instantly becomes single-tenant — no code change, just config.)

So the audience flag and the authority are the two halves of the same switch: one says “let other tenants instantiate me,” the other says “send their users to the door that allows it.” You never construct that authority by hand, though — in Step 3 a single AddMicrosoftIdentityWebApp(Configuration.GetSection(“AzureAd”)) call reads this exact block and wires the whole OpenID Connect handler from it.

Step 2 : Register the app

In the Entra portal I went to App registrations -> New registration. Three choices that matter: a name, the account type (Multiple Entra ID tenants), and a redirect URI. Because this is a server-side web app, I chose the Web platform and pointed it at https://localhost:7039/signin-oidc — the address Entra sends the user back to after they authenticate.

From the Overview I grabbed the Application (client) ID, then created a client secret under Certificates & secrets. The client ID is public and safe to commit; the secret is not — that goes into a git-ignored file, never the repo.

Step 3 : Wire it into ASP.NET Core

Two packages — Microsoft.Identity.Web and its UI — and a few lines in Program.cs:

The config section sets “TenantId”: “organizations” — the multi-tenant flag. I added a [Authorize] Dashboard page that simply dumps every claim, so I could actually see what Entra sends back.

Step 4 : The snag

First sign-in attempt blew up: AADSTS700054: response_type ‘id_token’ is not enabled for the application. The app was asking Entra to hand back a token directly in the browser (the old implicit flow), which I’d deliberately left disabled. The fix wasn’t to enable it — it was to use the better flow. One line:

options.ResponseType = OpenIdConnectResponseType.Code;

This switches to the authorization-code flow: the browser only gets a short-lived code, and my server quietly trades it for tokens using the client secret. More secure, and the error disappears.

Step 5 : See it work

Restart, open https://localhost:7039, click Sign in. Microsoft’s login page appears, I authenticate, accept the one-time consent prompt, and land back in the app — signed in. The server logs confirm the token’s signature, lifetime, and audience all validated.

That tid is the whole point — the thread I’ll pull next to isolate each company’s data and onboard new organizations. But the sign-in flow works: any company’s users can now authenticate and reach the app.

Code’s on GitHub.

Next up: making sure only onboarded tenants get in.


메타데이터
post_id
b00666201cb7
slug
building-a-multi-tenant-login-in-asp-net-core-with-microsoft-entra-id-b00666201cb7
url
https://medium.com/@sainitesh/building-a-multi-tenant-login-in-asp-net-core-with-microsoft-entra-id-b00666201cb7
canonical_url
https://medium.com/@sainitesh/building-a-multi-tenant-login-in-asp-net-core-with-microsoft-entra-id-b00666201cb7
author_url
https://medium.com/@sainitesh
status
ok
fetched_at
2026-06-26 21:52:29