Skip to content

Identity Providers Comparison

Key Points

  • Hosted (cloud) IdPs — Microsoft Entra ID (formerly Azure AD), Auth0, Okta, AWS Cognito, Google Identity Platform. Pay per user/MAU.
  • Self-hosted IdPsDuende IdentityServer (commercial since v6), OpenIddict (free, MIT), Keycloak (free, Java).
  • Senior choice in 2026 .NET ecosystem: Entra ID (if Microsoft shop), Auth0/Okta (best UX/integrations, paid), Duende (regulated/on-prem .NET), OpenIddict (free .NET on-prem), Keycloak (cross-stack).
  • ASP.NET Core Identity is not an IdP — it's a user store. Pair with Duende/OpenIddict if you need OAuth2/OIDC server.
  • The real choice driver: data residency, compliance, multi-tenant story, B2B/B2C, MFA needs, social logins, cost, vendor risk.

Concepts (deep dive)

Microsoft Entra ID

Microsoft's cloud IdP (renamed from Azure AD in 2023).

Feature Notes
Workforce Default for enterprises in M365
External Identities B2B (guest users), B2C (customer-facing app)
Conditional Access Risk-based policies, MFA enforcement
Verified ID Decentralized credentials
Microsoft.Identity.Web First-class .NET integration
builder.Services
    .AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));

Strengths: deep Microsoft integration, Conditional Access, enterprise SSO. Weaknesses: B2C is creaky and expensive; complex tenancy model.

Auth0 (Okta)

Cloud IdP focused on developer experience.

builder.Services
    .AddAuthentication(o => { o.DefaultScheme = "Cookies"; o.DefaultChallengeScheme = "Auth0"; })
    .AddCookie()
    .AddOpenIdConnect("Auth0", o =>
    {
        o.Authority = $"https://{domain}/";
        o.ClientId = clientId;
        o.ClientSecret = secret;
        o.ResponseType = "code";
        o.UsePkce = true;
    });

Strengths: best DX, social logins out of the box, robust SDKs, Actions/Rules for custom claim logic. Weaknesses: pricing scales fast (per MAU); Okta acquisition added enterprise focus.

Okta (Workforce)

Auth0's parent. Workforce IdP, dominant in US enterprises. Similar OIDC integration.

AWS Cognito

AWS-native IdP. Decent if you're all-in on AWS. Cheaper than Auth0 at scale. Less polish in customizations.

Duende IdentityServer

The successor to IdentityServer4. Self-hosted, .NET-native, OAuth2/OIDC server.

builder.Services.AddIdentityServer()
    .AddInMemoryClients(Config.Clients)
    .AddInMemoryIdentityResources(Config.IdentityResources)
    .AddInMemoryApiScopes(Config.ApiScopes)
    .AddAspNetIdentity<AppUser>()
    .AddDeveloperSigningCredential();

Important: Commercial license required for production since v6 (paid for >1M tokens/year, or for commercial use). Free for non-commercial / dev / very small.

Strengths: full control, on-prem, .NET-native, mature, customizable. Weaknesses: licensing cost; you operate it.

OpenIddict

Free, MIT-licensed alternative to Duende.

builder.Services.AddOpenIddict()
    .AddCore(o => o.UseEntityFrameworkCore().UseDbContext<AppDb>())
    .AddServer(o =>
    {
        o.SetTokenEndpointUris("/connect/token");
        o.SetAuthorizationEndpointUris("/connect/authorize");
        o.AllowAuthorizationCodeFlow().RequireProofKeyForCodeExchange();
        o.AllowClientCredentialsFlow();
        o.RegisterScopes("api");
        o.AddDevelopmentEncryptionCertificate().AddDevelopmentSigningCertificate();
    })
    .AddValidation(o => { o.UseLocalServer(); o.UseAspNetCore(); });

Strengths: free, well-maintained, similar API surface to Duende. Weaknesses: smaller community than Duende; less commercial support.

Keycloak

Free, Apache 2.0, Red Hat-maintained. Java-based. Cross-stack — works for non-.NET clients too.

.AddOpenIdConnect(o =>
{
    o.Authority = "https://keycloak/realms/myapp";
    /* ... */
});

Strengths: feature-rich (admin UI, realms, federation, MFA, social login). Weaknesses: Java operational cost; not .NET-native.

ASP.NET Core Identity

NOT an IdP. It's a user store + sign-in helpers + 2FA. To act as an OIDC server, pair with Duende or OpenIddict.

builder.Services.AddIdentityCore<AppUser>()
    .AddEntityFrameworkStores<AppDb>();

// + Duende or OpenIddict for OIDC endpoints

Or: use Identity for self-hosted user-facing login pages; emit cookies. No external clients.

Decision matrix

Need Recommendation
Microsoft shop, M365 Entra ID
Best DX, social logins Auth0
US enterprise SSO Okta
AWS-native Cognito
Self-hosted, regulated, .NET Duende (paid)
Self-hosted, free, .NET OpenIddict
Self-hosted, cross-stack, free Keycloak
User store + login UI only ASP.NET Core Identity

B2B vs B2C

  • B2B (workforce): Entra workforce, Okta, Duende. SSO, Conditional Access, federation.
  • B2C (customers): Entra External ID (formerly B2C), Auth0 Universal Login, Cognito. Sign-up flows, social logins, custom branding.

Multi-tenant SaaS considerations

  • Per-tenant IdP (each customer brings their own IdP via OIDC/SAML federation) — the most flexible enterprise pattern.
  • Single IdP, multi-tenant — your IdP holds users tagged by tenant. Simpler.
  • Auth0 Organizations and Entra External ID multi-tenant apps both support this.

Migration risks

Switching IdPs is hard:

  • User identifiers (sub claim) differ — re-link user records.
  • Federated identities (Google/MS personal) need re-consent.
  • Refresh tokens / sessions invalidated.
  • Custom claim logic (Auth0 Actions, Entra claims mappings) doesn't translate.

Plan for "dual issuer" period during migration — accept tokens from both old and new IdPs.

MFA & passwordless

Modern IdPs all support: - TOTP (Google Authenticator, Authy) - WebAuthn / FIDO2 / passkeys - SMS (deprecated for high-security) - Push notifications

For new apps, push for passkeys — phishing-resistant, no secret to steal.


Code: correct vs wrong

❌ Wrong: rolling your own OAuth server

// 5000 lines of token endpoint, JWKS rotation, PKCE verification...

Don't. Use Duende / OpenIddict / hosted IdP.

✅ Correct: configure trusted IdP

.AddOpenIdConnect(o => { o.Authority = "https://idp.contoso.com"; /* ... */ });

❌ Wrong: ASP.NET Core Identity for SSO across multiple apps

// Identity logs users in app A; app B has its own Identity → no SSO.

✅ Correct: front Identity with Duende/OpenIddict

builder.Services.AddIdentityCore<AppUser>().AddEntityFrameworkStores<AppDb>();
builder.Services.AddOpenIddict().AddCore(...).AddServer(...);

Design patterns for this topic

Pattern 1 — "Hosted IdP by default; self-hosted only when required"

  • Intent: lower operational burden.

Pattern 2 — "ASP.NET Identity + Duende/OpenIddict"

  • Intent: self-hosted with full OIDC server.

Pattern 3 — "Federation for B2B"

  • Intent: customer's IdP federates into yours; no user duplication.

Pattern 4 — "Multi-tenant via per-tenant authority"

  • Intent: tenant ID in the route → authority resolves dynamically.

Pattern 5 — "Dual issuer during migration"

  • Intent: accept tokens from old and new IdP for transition window.

Pros & cons / trade-offs

IdP Pros Cons
Entra ID Microsoft integration; CA Complex tenancy
Auth0 Best DX Pricing
Okta Enterprise SSO Enterprise pricing
Cognito AWS-native Less customizable
Duende .NET-native License cost
OpenIddict Free; .NET Smaller community
Keycloak Free; cross-stack Java ops
Identity (alone) Self-host user store Not an IdP

When to use / when to avoid

  • Use hosted IdP unless compliance/data-residency forces self-hosting.
  • Use Duende/OpenIddict when self-hosting on .NET.
  • Avoid rolling your own OAuth — full of footguns.
  • Avoid Identity-only if you need SSO across apps.

Interview Q&A

Q1. Is ASP.NET Core Identity an IdP? No — it's a user store and sign-in helper. Pair with Duende or OpenIddict to act as an OAuth2/OIDC server.

Q2. When choose Duende over Auth0? On-prem requirement, regulated data, full customization, or massive scale where Auth0's per-MAU pricing dominates Duende's flat fee.

Q3. What's Entra External ID? Microsoft's customer-identity offering (replaces B2C). Sign-up, social logins, custom branding for customer-facing apps.

Q4. Why prefer hosted IdP for most apps? Security maturity, MFA, attack-detection, compliance certifications. Hard to match self-hosted.

Q5. What's federation? Trusting an external IdP (customer's, partner's). Your IdP issues its own token but trusts the external one for identity assertion.

Q6. How do you migrate IdPs? Dual-issue period; accept both old and new tokens; re-link user records by email or external ID; force re-consent at cutover.

Q7. When use Keycloak in a .NET shop? Cross-stack environments (mix of Java/Node/.NET) where one IdP serves all. Or if licensing rules out Duende and you don't want OpenIddict.

Q8. What's a confidential vs public client? Confidential = can hold a secret (server-side web app, daemon). Public = can't (SPA, mobile). PKCE makes public clients viable.

Q9. Why are passkeys important? WebAuthn/FIDO2 phishing-resistant credentials bound to origin. Replace passwords entirely. Senior teams should be planning rollouts.

Q10. Multi-tenant: shared vs per-tenant authority? Shared: one IdP, tenant claim per user. Per-tenant: dynamic authority (https://idp/{tenant}/v2.0). Per-tenant scales to enterprise federation.


Gotchas / common mistakes

  • ⚠️ Mixing two self-hosted IdPs — duplicate users; no SSO.
  • ⚠️ Hosting IdP on the same domain as the appCSRF/SameSite weirdness.
  • ⚠️ Logging tokens in console output — accidentally leaking credentials.
  • ⚠️ Default Auth0 / Cognito quotas — production traffic blows past them.
  • ⚠️ Hard-coding client_secret in repo — use Key Vault / managed identity.
  • ⚠️ Not planning IdP migration — coupling assumptions to vendor.

Further reading