Sarıkaya Dev Logo

Implement Multi‑Tenant SaaS in .NET 8 with Azure AD B2C, Duende and EF Core Sharding

Mahmut Sarıkaya 4 min read 4 Views 0
Implement Multi‑Tenant SaaS in .NET 8 with Azure AD B2C, Duende and EF Core Sharding

Why Multi‑Tenant SaaS Matters in .NET 8

Enterprises are demanding cloud platforms that can host hundreds of customers on a single code base while keeping data isolated. A recent Gartner survey reported that 78% of SaaS providers plan to adopt multi‑tenant architectures by 2025 to cut operational costs. .NET 8 brings native support for minimal APIs, improved performance, and built‑in support for source generators, making it an ideal foundation for a scalable multi‑tenant solution.

Choosing the Right Identity Stack

Identity is the most sensitive layer in a SaaS product. Azure AD B2C excels at consumer‑grade sign‑in experiences and social logins, but it does not provide fine‑grained API authorization out of the box. Duende IdentityServer fills that gap by offering OAuth2/OpenID Connect flows that can be customized per tenant. Combining both gives you a seamless front‑door (B2C) and a powerful back‑door (IdentityServer) for API protection.

Setting Up Azure AD B2C for Tenant Isolation

Start by creating a single Azure AD B2C tenant that will act as the identity provider for all SaaS customers. Within the B2C tenant, define a custom attribute called tenantId and expose it as a claim. This claim will travel with every token and let downstream services identify the owning tenant without additional lookups.

az ad b2c tenant create --name MySaaS-B2C --resource-group rg-saas --location eastus

Next, add the custom attribute via the Azure portal or CLI:

az ad b2c extension-property create --name tenantId --data-type string --target-object-type users

When configuring a user flow, map the tenantId attribute to a token claim called tfp (or any name you prefer). Your client applications will receive this claim after a successful sign‑in, enabling per‑tenant logic in .NET code.

Integrating Duende IdentityServer with .NET 8

Duende IdentityServer runs as a separate ASP.NET Core service. In .NET 8 you can use the new WebApplication builder to keep the startup concise. The following snippet shows how to register IdentityServer, load the B2C configuration, and add a custom profile service that injects the tenantId claim into access tokens.

var builder = WebApplication.CreateBuilder(args);\n\nbuilder.Services.AddIdentityServer(options =>\n{\n    options.EmitStaticAudienceClaim = true;\n})\n.AddInMemoryClients(Config.GetClients())\n.AddInMemoryIdentityResources(Config.GetIdentityResources())\n.AddInMemoryApiScopes(Config.GetApiScopes())\n.AddDeveloperSigningCredential();\n\nbuilder.Services.AddTransient<IProfileService, TenantProfileService>();\n\nvar app = builder.Build();\napp.UseIdentityServer();\napp.Run();

The TenantProfileService reads the incoming B2C token, extracts the tenantId claim, and adds it to the issued access token:

public class TenantProfileService : IProfileService\n{\n    public Task GetProfileDataAsync(ProfileDataRequestContext context)\n    {\n        var tenantId = context.Subject.FindFirst("tenantId")?.Value;\n        if (!string.IsNullOrEmpty(tenantId))\n        {\n            context.IssuedClaims.Add(new Claim("tenantId", tenantId));\n        }\n        return Task.CompletedTask;\n    }\n\n    public Task IsActiveAsync(IsActiveContext context) => Task.CompletedTask;\n}

Now every API call protected by IdentityServer carries the tenant identifier, allowing downstream services to enforce data isolation.

Implementing EF Core Sharding for Data Isolation

EF Core 8 introduces built‑in sharding support through the UseSharding extension. The idea is to route queries to a tenant‑specific database based on the tenantId claim extracted from the HttpContext. First, define a TenantInfo class that holds the connection string for each tenant.

public class TenantInfo\n{\n    public string TenantId { get; set; }\n    public string ConnectionString { get; set; }\n}

Register a scoped service that resolves the current tenant from the token:

builder.Services.AddScoped<TenantInfo>(sp =>\n{\n    var httpContext = sp.GetRequiredService<IHttpContextAccessor>().HttpContext;\n    var tenantId = httpContext.User.FindFirst("tenantId")?.Value;\n    // In a real world app, look up the connection string from a secure store\n    var conn = $\"Server=sql-prod;Database=Tenant_{tenantId};User Id=sa;Password=StrongPwd!\";\n    return new TenantInfo { TenantId = tenantId, ConnectionString = conn };\n});

Configure the DbContext to use the tenant’s connection string at runtime:

builder.Services.AddDbContext<AppDbContext>(options =>\n{\n    var tenantInfo = options.GetService<TenantInfo>();\n    options.UseSqlServer(tenantInfo.ConnectionString);\n});

When you query AppDbContext, EF Core automatically directs the command to the correct database shard, guaranteeing physical data isolation without writing custom interceptors.

Deploying and Scaling on Azure

Azure Kubernetes Service (AKS) is a natural host for this architecture. Deploy IdentityServer as a separate microservice behind an Azure Application Gateway that terminates TLS and forwards B2C tokens. The API layer, built with .NET 8 minimal APIs, can be scaled horizontally; each pod reads the tenant claim and connects to its own Azure SQL Database shard.

Monitoring is critical. Enable Azure Monitor for containers, and use Application Insights to capture the tenantId as a custom dimension. This lets you slice logs per tenant and quickly spot performance regressions.

Conclusion

By marrying Azure AD B2C, Duende IdentityServer, and EF Core sharding, you can construct a truly multi‑tenant SaaS platform on .NET 8 that delivers both security and performance. The key steps are: expose a tenant identifier via B2C, propagate it through IdentityServer, and let EF Core route queries to tenant‑specific databases. The result is a clean separation of concerns, easier compliance, and a cost‑effective scaling model on Azure.

Sources

  • Microsoft Azure AD B2C Documentation
  • Duende IdentityServer Official Guides
  • EF Core 8 Sharding Overview – Microsoft Docs

Author: Mahmut Sarıkaya — sarikayadev.com

Tags: #dotnet 8 multi‑tenant #azure ad b2c #duende identityserver #ef core sharding #saas architecture .net
Share:
M

Written by

Mahmut Sarıkaya

Software Developer

Comments

No comments yet. Be the first to share your thoughts!

Leave a Comment

3 + 2 =