All entries
- PostgreSQL or SQL Server - how do they differ, and when is migrating from one to the other worth it?
Neither is faster in general. Move to PostgreSQL to drop per-core licences, run on any host and gain its types and extensions. Move to SQL Server for the Microsoft data stack, columnstore analytics, or a vendor that certifies only it. Migrate only when that gain beats the cost, which is in the code (procedures, dialect, collation, locking), not the data.
- What database schema links an Entra ID (or other SSO) identity to an existing local user table?
Add a separate external-logins table - one row per (provider, tenant, subject) triple with a foreign key to the local user - instead of touching the existing user/auth table at all. Key it on the ID token's `oid` plus `tid` - Microsoft's guidance for sharing an identity across services, and what lets a tenant be revoked; cache claims and refresh tokens there too, never in the local user row. First sign-in looks the pair up in that table; on no match it links by email only if the app opts in and the token carries `xms_edov: true`, else creates the user and the login in one transaction.
- How do I add a second JWT bearer authentication scheme to an ASP.NET Core API without it conflicting with the existing one?
Register each handler under its own scheme name, `AddJwtBearer("Legacy", ...)` and `AddMicrosoftIdentityWebApi(config, jwtBearerScheme: "EntraId")`; two unnamed ones both default to `"Bearer"` and throw on startup. Pick a scheme per request with `[Authorize(AuthenticationSchemes = "Legacy,EntraId")]`, or automatically via `AddPolicyScheme`'s `ForwardDefaultSelector`, reading the token's unvalidated `iss` claim. Either way each scheme still fully validates the token itself; the selector only routes, it never authenticates.
- How do I coordinate Microsoft Entra ID sign-in between a single-page app and a separately hosted backend API?
A bearer-token SPA runs MSAL.js itself and attaches its own access token to calls the API's CORS policy allows across origins - simplest to stand up, but every token lives in the browser. A backend-for-frontend (BFF) makes the backend the confidential OIDC client instead: it owns the redirect, keeps tokens server-side, and hands the SPA a same-origin cookie needing no CORS setup. Default to the BFF when the backend can own a session; reach for the bearer-token SPA only when the API also has to serve other, non-browser callers with the same token.
- How do I validate Microsoft Entra ID access tokens on the server to protect an API?
Register JWT bearer auth with the tenant's Authority and Audience (`AddMicrosoftIdentityWebApi`, or `AddJwtBearer`): it fetches Entra's keys and checks signature, issuer, audience and expiry before any handler runs. A valid signature only proves Entra ID issued the token, not that it targets this API - check the audience, and require a scope or app role with `[Authorize]` plus a permission check. Never decode a bearer token by hand and trust its claims: an unvalidated token is only as trustworthy as a header the caller typed in.
- What is single sign-on and how do OAuth 2.0 and OpenID Connect implement it with Microsoft Entra ID?
Single sign-on is a property - one login session trusted by several apps - not a protocol; OAuth 2.0 supplies the access token an API needs, and OpenID Connect adds the ID token that says who signed in. Microsoft Entra ID is the authorization server (identity provider) for both: one sign-in issues an ID token plus an access token, and a second app in the same tenant reuses that session instead of prompting again. Authorization Code with PKCE is the flow for anything with a sign-in UI; a server-to-server call with no user present uses client credentials instead.
- How do I add Microsoft Entra ID sign-in to a web app or single-page app?
Register the app in the Microsoft Entra admin center under the matching platform type - Single-page application for a SPA, Web for a server-rendered app. Then run authorization code with PKCE through a library instead of by hand: MSAL.js for a SPA, Microsoft.Identity.Web for ASP.NET Core. Call the silent token method first and fall back to an interactive one only when it throws, so a returning user isn't reprompted every page load.
- How do I attach a bearer token to every HttpClient request with a DelegatingHandler?
Override `SendAsync` in a `DelegatingHandler` subclass to set `request.Headers.Authorization`, register the handler `Transient`, and chain `.AddHttpMessageHandler<TheHandler>()` onto the client's `AddHttpClient(...)` registration - never set the header on the client itself.
- What is the right way to authenticate a .NET desktop client against an API that issues JWTs?
Run OAuth 2.0 Authorization Code with PKCE in the system browser, not an embedded WebView, landing the callback on a loopback address or a registered custom URI scheme, rather than collecting the password in app code. Store the access and refresh tokens in the OS credential store (DPAPI-backed on Windows), never in a config file. Treat the JWT as an opaque bearer token the client attaches to requests but never decodes to decide what the user may do.
- What project structure fits a WPF app that calls a REST API with CommunityToolkit.Mvvm?
One project, folders by role - Models, ViewModels, Views, Services (the API client behind an interface) - wired up with the .NET Generic Host in `App.xaml.cs`: it builds the DI container, registers a typed `HttpClient` for the API and the windows/view models, and resolves `MainWindow` from it instead of `StartupUri`.
- Should a WPF app use an MVVM framework, or is plain WPF and modern C# enough?
Use one: CommunityToolkit.Mvvm for the boilerplate (property-changed notification, commands) via source generators, plus Prism if the app also needs region-based navigation or a module system. Prism's DI container is not the reason to add it: the .NET Generic Host gives any WPF app a DI container on its own, and Prism 9's own container is dual-licensed, free only below a revenue or a funding threshold. Modern C# removed the reason to write `INotifyPropertyChanged` by hand, not the value of not writing it.