Blog
Mert Özen's blog posts on software development, backend, frontend, and DevOps.
What Changed in Authentication and Identity from ASP.NET Core 6 to 11
The most important authentication changes from ASP.NET Core 6 to 10 don't break the build; they silently change behavior. We run the same code on .NET 6, 8 and 10 to show a single scheme becoming the default, SecurityToken turning into JsonWebToken, cookies returning 401 instead of 302 for APIs and the new metrics; then cover PAR in .NET 9, .NET 11's TimeProvider, passkey names and DBSC, and a migration checklist.
Authentication State in Angular: Functional Guards, Interceptors, Single-Flight Token Refresh and UI Authorization
Guards and hidden buttons in Angular are user experience, not a security boundary; the real decision is made in the API. We write a signal-based auth state service, canMatch guards, a permission directive, an interceptor that ties concurrent 401s to a single refresh, and cross-tab sign-out with BroadcastChannel, test them all with Vitest, and show that a request bypassing the guard gets a 403 from the API.
Authorization Models: RBAC, ABAC, ReBAC and Permission-Based Design in Multi-Tenant Scenarios
Stuffing conditions into roles leads to role explosion; the fix is to use RBAC, ABAC and ReBAC as layers. We reduce roles to permission bundles, write the refund rule as a policy that returns reasoned decisions from tenant, limit and time attributes, show the Zanzibar idea with a toy relationship graph, pin it all with tests, and discuss permissions in tokens, the tenant claim and auditing impersonation.
Choosing an Authorization Server: Comparing OpenIddict, Duende IdentityServer, Keycloak and Microsoft Entra ID
The right authorization server depends on what your team can operate: OpenIddict and Duende are frameworks, Keycloak a product, Entra ID a managed service. We run three in the lab, build a capability matrix from discovery documents, show why it must be read with care, and compare licenses, operational load, SAML bridging and why you should not write your own authorization server, as of November 2026.
The BFF Pattern for SPAs: The Architecture RFC 10017 Recommends with Angular, ASP.NET Core and YARP
There is no safe place for tokens in the browser; the option RFC 10017 rates most secure is a BFF that keeps tokens on the server. In ASP.NET Core 10 we set up OIDC with a cookie session, attach tokens via YARP on the way to the API, renew tokens inside the BFF, defend against CSRF with a custom header and build an XHR-friendly logout; curl output shows Angular never sees a token, and we weigh the costs.
Protecting the API: Access Token Validation, Audience, Scope Policies, Client Credentials and DPoP
An API must accept not every validly signed token, but only one issued for its own audience and carrying the required scope. We wire AddJwtBearer to Keycloak, map scopes to policies, use introspection to show why a signed-out user's JWT still passes, write a DelegatingHandler that caches client credentials tokens, and verify in five scenarios that a stolen DPoP-bound token is useless.
OpenID Connect: ID Tokens, UserInfo, Discovery, AddOpenIdConnect in ASP.NET Core and Logout Types
An ID token is a sign-in record written for the client, an access token is a permission written for the API; mixing them up is a vulnerability. In a Keycloak lab we read discovery, JWKS and UserInfo, show how MapInboundClaims renames claims in AddOpenIdConnect, trace RP-initiated logout, and write a back-channel logout endpoint that drops this app's cookie when the user signs out of another app.
Authorization Code Flow + PKCE Step by Step: state, nonce, PAR and Reading the HTTP Traffic with Keycloak
PKCE binds the code that crosses the front channel to the client that asked for it; a stolen code is useless without the verifier. In a Keycloak lab we read the flow step by step with curl, show what state and nonce prevent, that a code is burned after a wrong verifier and why redirect URIs must match exactly; then we move parameters to the back channel with PAR and trace ASP.NET Core's OIDC handler end to end.
The Logic of OAuth 2.0: Roles, Grant Types, Scopes and What RFC 9700 and OAuth 2.1 Bring
OAuth 2.0 is a delegation protocol, not a sign-in protocol. We run the four roles, the front/back channel split, confidential vs public clients, and the authorization code, client credentials and device grants against a Keycloak lab with .NET 10 code; then show why implicit and password grants were removed, what RFC 9700 and the OAuth 2.1 draft bring, and why an access token is not proof of sign-in.
Refresh Tokens: Rotation, Reuse Detection, Revocation and Secure Server-Side Storage
A refresh token should be replaced on every use, and if a consumed token comes back, the whole token family of that sign-in should be revoked; RFC 9700 requires this or sender-constrained tokens for public clients. With EF Core and SQLite we build SHA-256 hashed storage, atomic consumption with ExecuteUpdate, reuse detection, the two-tab race, sliding and absolute lifetimes and signing out of all devices with real outputs.
JWT in Depth: JWS and JWE, Algorithm Choice, kid, JWKS and Signing Key Rotation
Seamless signing key rotation takes three steps: publish the new key in the JWKS, wait until the APIs' caches refresh (12 hours by default), then sign with it and retire the old key once token lifetimes pass. We show JWS versus JWE, choosing ES256, alg none and algorithm confusion attempts, typ validation with at+jwt, kid and JWKS, the 8725bis draft's warnings and claim bloat with real outputs.
Passkeys 2: Passkey Registration and Passwordless Sign-in with ASP.NET Core Identity 10 and an Angular Client
ASP.NET Core Identity 10 ships passkey registration and passwordless sign-in through SignInManager's MakePasskeyCreationOptionsAsync, PerformPasskeyAttestationAsync and PasskeySignInAsync; but with an empty ServerDomain the RP ID comes from the Host header, and a passkey sign-in writes pwd as amr. We build the Angular client, conditional UI and an end-to-end test with headless Chrome's virtual authenticator.