Skip to main content
Article complete

Get one like this every Tuesday at 7 PM IST.

codewithmukesh
Back to blog
dotnet webapi-course 14 min read New

Identity API Endpoints in ASP.NET Core: When to Use Them (.NET 10)

MapIdentityApi gives you register, login, and refresh for free in .NET 10. Here is exactly when to use Identity API endpoints and when to roll your own.

MapIdentityApi gives you register, login, and refresh for free in .NET 10. Here is exactly when to use Identity API endpoints and when to roll your own.

dotnet webapi-course

identity-api-endpoints mapidentityapi aspnet-core-identity dotnet-10 authentication bearer-token jwt addidentityapiendpoints minimal-api spa-authentication blazor-authentication web-api api-security identity register-endpoint refresh-token cookie-authentication opaque-token

Mukesh Murugan
Mukesh Murugan
Software Engineer

Use ASP.NET Core Identity API endpoints when you need first-party login fast - a SPA, Blazor, or mobile app where you control both ends and just need register, login, and refresh without writing them. Skip them the moment you need a real JWT, social login, custom registration fields, or the ability to lock down /register. One MapIdentityApi() call adds ten authentication endpoints to your API. This guide shows exactly where that trade pays off and where it traps you.

In the JWT authentication article I built login from scratch: an Identity user store, a token service, validation parameters, the works. That is the control-everything path. Identity API endpoints are the opposite path - one method call and the entire register/login/refresh surface exists. The question this article answers is not “how do I set it up” (that part is three lines). It is “should I, and what does saying yes cost me later.”

Everything here runs on a single .NET 10 Minimal API project you can clone and hit F5 on. Let’s get into it.

What Are Identity API Endpoints?

Identity API endpoints are a set of prebuilt Minimal API endpoints - register, login, refresh, and more - that ASP.NET Core adds with a single MapIdentityApi<TUser>() call, backed by ASP.NET Core Identity. They were introduced in .NET 8 and are current in .NET 10. They issue opaque bearer tokens, not JWTs, and are designed for first-party SPA, Blazor, and mobile clients.

Before .NET 8, wiring up Identity for an API meant either dragging in the Razor Pages UI (designed for server-rendered MVC apps, awkward for a JSON API) or hand-rolling every endpoint. MapIdentityApi closed that gap. It is the JSON-API equivalent of the old Identity UI: the same UserManager, SignInManager, and password hashing underneath, exposed as HTTP endpoints a frontend can call.

The whole thing is built on ASP.NET Core Identity. If you already know UserManager<TUser> and IdentityDbContext, you already know the engine. MapIdentityApi is just a thin endpoint layer bolted on top.

The Three-Line Setup

Here is the entire setup. Add the Identity services, point them at a store, map the routes:

Program.cs
var builder = WebApplication.CreateBuilder(args);
// In-memory store so the demo is F5-ready. Swap for SqlServer/Sqlite for real use.
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseInMemoryDatabase("IdentityDemo"));
builder.Services.AddAuthorization();
// This one call registers the Identity API endpoint services + bearer token handling.
builder.Services.AddIdentityApiEndpoints<IdentityUser>()
.AddEntityFrameworkStores<AppDbContext>();
var app = builder.Build();
// And this one maps all ten endpoints under the app root.
app.MapIdentityApi<IdentityUser>();
app.Run();

The AppDbContext is a standard IdentityDbContext:

Data/AppDbContext.cs
public class AppDbContext(DbContextOptions<AppDbContext> options)
: IdentityDbContext<IdentityUser>(options);

That is it. Run the app, open Scalar (or the .http file in the repo), and you have a working registration and login flow. I tested this on .NET 10 with Microsoft.AspNetCore.Identity.EntityFrameworkCore 10.0.0. The complete source is on GitHub.

Two things worth noticing already. First, AddIdentityApiEndpoints (not the older AddIdentity) is what turns on the API-flavored bearer token support. Second, MapIdentityApi adds the routes at the root by default - /register, /login, and so on. To namespace them, wrap the call in a group:

Program.cs
// Now everything lives under /account: /account/register, /account/login, ...
app.MapGroup("/account").MapIdentityApi<IdentityUser>();

What Endpoints Does MapIdentityApi Add?

The call to MapIdentityApi<TUser> adds exactly these ten endpoints:

MethodRoutePurpose
POST/registerCreate a new user from email + password
POST/loginSign in, get a cookie or bearer token
POST/refreshExchange a refresh token for a new access token
GET/confirmEmailConfirm an email address via the emailed link
POST/resendConfirmationEmailResend the confirmation email
POST/forgotPasswordStart a password reset (sends a code)
POST/resetPasswordComplete a password reset with the code
POST/manage/2faEnable, disable, or reset two-factor auth
GET/manage/infoRead the current user’s email and claims
POST/manage/infoUpdate the current user’s email or password

That covers the full lifecycle of a first-party account: sign up, confirm, log in, stay logged in, reset a forgotten password, and turn on 2FA. For a lot of apps, that is genuinely everything the auth layer needs to do.

One endpoint that is conspicuously absent: there is no /logout. MapIdentityApi does not map one. For cookie-based clients you add it yourself with SignInManager.SignOutAsync(); for token-based clients you just drop the token on the client side. That asymmetry is a small preview of the larger theme - the endpoints cover the common path and leave the rest to you, with no seam to extend them.

Cookies or Tokens? The Default Nobody Reads

When you call AddIdentityApiEndpoints, both cookie and token authentication are wired up at once. Which one /login issues depends on a single query string parameter:

Cookie mode
POST /login?useCookies=true
Token mode
POST /login

Set useCookies=true and login returns a Set-Cookie header; the browser carries it automatically on every later request. Omit it (or set it to false) and login returns a token in the response body instead.

Here is the part most tutorials skip: Microsoft recommends cookies for browser-based apps, not tokens. Straight from the docs - “We recommend using cookies for browser-based applications, because, by default, the browser automatically handles them without exposing them to JavaScript.” The token option exists for clients that cannot use cookies, like a native mobile app. If your frontend is a SPA on the same site as your API, cookies are the safer, simpler default. Storing a bearer token in localStorage to authenticate a browser app is the thing the cookie default is steering you away from.

A token-mode login returns this shape:

POST /login response
{
"tokenType": "Bearer",
"accessToken": "CfDJ8N...very long opaque string...",
"expiresIn": 3600,
"refreshToken": "CfDJ8N...another opaque string..."
}

By default the access token lives for one hour (expiresIn is 3600 seconds) and the refresh token for 14 days. You change both through BearerTokenOptions - BearerTokenExpiration and RefreshTokenExpiration respectively. You send the access token on later requests as a normal bearer header, and call /refresh with the refresh token when it expires:

Authorization: Bearer CfDJ8N...

This looks exactly like a JWT flow. It is not. That accessToken is where the most important decision in this article lives.

The Catch: That Token Is Not a JWT

Take the accessToken from a token-mode login and paste it into jwt.io. It will not decode. There is no header, no payload, no readable claims - just an encrypted blob.

This is by design, and it is the single most important fact about Identity API endpoints. From the official Microsoft Learn documentation: “The tokens aren’t standard JSON Web Tokens (JWTs). The use of custom tokens is intentional, as the built-in Identity API is meant primarily for simple scenarios.” The token is a proprietary, data-protection-encrypted string that only the issuing app can read. Microsoft is explicit that it “isn’t intended to be a full-featured identity service provider or token server.”

That one design choice has consequences that decide whether these endpoints fit your architecture:

  • Nothing can read the token but the app that issued it. A JWT carries claims any service can validate with the signing key. This token carries nothing readable. An API gateway, a second microservice, a downstream API - none of them can inspect it or trust it without calling back to the issuing app.
  • You cannot put custom claims in it. No tenant_id, no role your other services read, no subscription_tier. The token is a key to a server-side session, not a carrier of data.
  • It only works inside one app. The moment your system is more than a single API plus its own frontend, the opaque token stops being enough.

For a self-contained SPA-plus-its-own-API, none of that matters - the same app issues and validates the token, so an opaque blob is fine. For anything that needs to share identity across services, it is a wall. Knowing which situation you are in is the whole decision.

When to Use Identity API Endpoints

Reach for MapIdentityApi when all of these are true:

  • It is first-party auth. Your users register and log in directly with your app using email and password. You are not federating identity from Google, Microsoft, or a corporate IdP.
  • One app issues and consumes the token. A SPA, Blazor WebAssembly, or mobile app talking to its own API. No second service needs to validate the token independently.
  • The default user shape is enough. Email, password, the standard Identity columns. You are not collecting custom fields at registration or stuffing custom claims into the token.
  • You want it done today. Prototypes, internal tools, MVPs, side projects, course demos. The endpoints turn a day of auth plumbing into three lines.

This is not a small set of apps. A huge number of real projects are exactly “a SPA and the API behind it, with email-and-password login.” For those, MapIdentityApi is the right call and writing your own would be wasted effort. You get registration, email confirmation, password reset, refresh tokens, and 2FA - all tested, all maintained by the framework team - for free.

When NOT to Use Them

Walk away from MapIdentityApi the moment any of these is on your roadmap:

  • You need a real JWT. Any time another service, gateway, or API has to validate the token without phoning home, you need a signed JWT with readable claims. The opaque token cannot do this. This is the most common reason teams rip the endpoints out.
  • You need social or OIDC login. “Sign in with Google” or any OpenID Connect provider is out of scope for these endpoints. They are first-party only. Bolting OIDC on later means a different system entirely.
  • You need custom registration fields. The /register body is fixed at { email, password }. Want a FirstName, a CompanyName, a TenantId at sign-up? You cannot extend the endpoint’s request body. You would intercept and patch afterward, which is fragile.
  • You need to disable or rename endpoints. /register is always public. There is no built-in switch to remove it, so an invite-only app cannot simply turn registration off. You also cannot rename routes - this is the source of the awkward /manage/info paths. These limitations are well-documented in open issues on the dotnet/aspnetcore repo (for example, issues #50303 and #57899 on endpoint filtering and customization).
  • You need fine-grained control over the auth flow. Custom lockout logic, audit logging on every login attempt, a bespoke token lifetime per client - the endpoints are a black box. You configure what Identity exposes as options, and no more.

Notice the pattern: every “don’t” is about needing a seam the endpoints do not give you. They are intentionally closed. That is what makes them fast, and also what makes them a dead end when requirements grow.

Decision Matrix: Identity Endpoints vs Custom JWT vs OIDC Provider

Three realistic options for authentication in a .NET API, and where each one wins:

ConcernIdentity API EndpointsCustom JWT (roll your own)OIDC Provider (Keycloak, Entra, Auth0)
Setup effortLowest (3 lines)Medium (you write the endpoints)Medium-high (stand up / configure a provider)
Token typeOpaque, app-onlySigned JWT with your claimsSigned JWT / OIDC tokens
Custom claimsNoYesYes
Social / external loginNoDIY, painfulBuilt-in
Works across microservicesNoYesYes
Custom registration fieldsNoYesYes (with config)
Disable / customize endpointsNoFull controlFull control
Maintenance burdenFramework owns itYou own itProvider owns it
Best forFirst-party SPA/mobile, MVPsA few services, custom claims, no IdPMany services, SSO, enterprise, social login

The honest read: Identity endpoints and a full OIDC provider sit at two ends, and custom JWT is the pragmatic middle for the very common case of “I need real tokens with my own claims, but I do not want to run Keycloak.” That middle path is worth its own section, because you can get there without throwing away Identity.

My Take

Use Identity API endpoints when the app is small enough that you can honestly promise it will never need cross-service tokens or social login. For a solo SPA, a Blazor app, a mobile MVP - ship it, the three-line version is correct and anything more is over-engineering.

But the day you can feel “we will probably need Google login” or “the mobile API and the web API will both validate this token,” do not start on MapIdentityApi and plan to migrate. There is no clean migration. The opaque token is woven into how the endpoints work, and swapping it for a JWT means rewriting the auth surface anyway. Starting on custom JWT from day one costs you an afternoon. Migrating off Identity endpoints under deadline costs you a sprint and a security review. Pick based on where the product is going, not only where it is today.

The Escape Hatch: Keep Identity, Drop MapIdentityApi

Here is the part that resolves the false choice. ASP.NET Core Identity and MapIdentityApi are not the same thing. MapIdentityApi is one (closed) way to expose Identity over HTTP. You can keep everything valuable about Identity - the user store, password hashing, lockout, SignInManager, 2FA support - and simply not call MapIdentityApi. Instead you write a thin login endpoint that issues a real JWT.

This is the middle path from the matrix, and it is not much code. Register Identity the normal way (note AddIdentity, not AddIdentityApiEndpoints):

Program.cs
builder.Services.AddIdentity<IdentityUser, IdentityRole>()
.AddEntityFrameworkStores<AppDbContext>();

Then a custom /auth/login that leans on SignInManager for the password check and your own token service for the JWT:

Endpoints/AuthEndpoints.cs
app.MapPost("/auth/login", async (
LoginRequest request,
UserManager<IdentityUser> userManager,
SignInManager<IdentityUser> signInManager,
TokenService tokenService) =>
{
var user = await userManager.FindByEmailAsync(request.Email);
if (user is null)
return Results.Unauthorized();
// CheckPasswordSignInAsync handles hashing + lockout for you.
var result = await signInManager.CheckPasswordSignInAsync(
user, request.Password, lockoutOnFailure: true);
if (!result.Succeeded)
return Results.Unauthorized();
var roles = await userManager.GetRolesAsync(user);
// Your TokenService issues a real, signed JWT with whatever claims you want.
var token = tokenService.CreateToken(user, roles);
return Results.Ok(new { accessToken = token });
});
public record LoginRequest(string Email, string Password);

You keep Identity doing what it is genuinely good at - storing users, hashing passwords, enforcing lockout - and you own the token. Now the token is a JWT, carries your claims, and validates across services. The TokenService here is exactly the one from the JWT authentication guide, and pairing it with refresh tokens gives you the same “stay logged in” experience MapIdentityApi provided, on tokens you control.

This is what I reach for in most real APIs: Identity for the user store, my own endpoints for the token. It is barely more code than MapIdentityApi and it has none of the walls.

Testing the Endpoints

With the MapIdentityApi version running, the happy path is two requests. Register:

POST /register
{
"email": "dev@codewithmukesh.com",
"password": "Passw0rd!"
}

A success returns 200 OK with an empty body. The password must satisfy the default Identity rules - at least six characters with an uppercase letter, a lowercase letter, a digit, and a non-alphanumeric character - or you get a 400 with a ProblemDetails body listing exactly which rule failed. Those validation errors come back in RFC 9457 Problem Details format, which the endpoints give you for free.

Then log in for a token:

POST /login
{
"email": "dev@codewithmukesh.com",
"password": "Passw0rd!"
}

You get the accessToken / refreshToken pair. Call a protected endpoint with the access token, and when expiresIn runs down, POST the refresh token to /refresh for a fresh pair. Try to register with a weak password or log in with the wrong one and you will see the 400 and 401 responses respectively - worth exercising so you know what your frontend has to handle.

Key Takeaways

  • MapIdentityApi<TUser>() adds ten authentication endpoints - register, login, refresh, email confirmation, password reset, and 2FA management - backed by ASP.NET Core Identity, in one line.
  • The tokens are opaque, not JWTs. They are app-only encrypted strings with no readable claims, intentionally limited to simple, single-app scenarios.
  • Use them for first-party SPA, Blazor, and mobile apps where one app issues and consumes the token and the default email/password user shape is enough.
  • Avoid them when you need real JWTs, social/OIDC login, custom registration fields, or the ability to disable /register - there is no seam to add any of those.
  • You can keep Identity and drop MapIdentityApi - use SignInManager for the password check and issue your own signed JWT. That middle path has Identity’s safety with none of the endpoint limitations.

FAQ

Are ASP.NET Core Identity API endpoint tokens JWTs?

No. The tokens issued by MapIdentityApi are opaque, proprietary bearer tokens encrypted with ASP.NET Core data protection, not standard JWTs. They carry no readable claims and can only be validated by the app that issued them. Microsoft made this choice intentionally because the endpoints target simple, single-app scenarios. If you need a signed JWT with claims that other services can read, write a custom login endpoint instead.

What endpoints does MapIdentityApi add?

It adds ten endpoints: POST /register, POST /login, POST /refresh, GET /confirmEmail, POST /resendConfirmationEmail, POST /forgotPassword, POST /resetPassword, POST /manage/2fa, GET /manage/info, and POST /manage/info. There is no /logout endpoint; you add that yourself if you need it.

How do I disable the /register endpoint in Identity API endpoints?

There is no built-in way to remove or disable a single endpoint from MapIdentityApi. The endpoints are added as a fixed set. If you need an invite-only app with no public registration, the practical options are to put the registration route behind a gateway rule, copy the source of the endpoint extension and map only the routes you want, or skip MapIdentityApi entirely and write your own endpoints.

Can I add custom fields like FirstName to the Identity register endpoint?

Not directly. The /register request body is fixed at email and password and cannot be extended through configuration. To collect custom fields at registration you would either patch the user in a separate call after registration, which is fragile, or write your own registration endpoint using UserManager. The custom endpoint route is the clean solution.

Do Identity API endpoints support Google or external login?

No. Identity API endpoints handle first-party email-and-password authentication only. They do not support OpenID Connect or external providers like Google, Microsoft, or Apple. If you need social or federated login, use an OIDC provider such as Keycloak, Microsoft Entra ID, or Auth0, or implement external authentication separately.

Should I use Identity API endpoints or custom JWT authentication?

Use Identity API endpoints for a first-party SPA, Blazor, or mobile app where a single app issues and consumes the token and the default user shape is enough. Use custom JWT authentication when you need readable claims, tokens that validate across multiple services, custom registration data, or full control over the auth flow. A good middle path keeps ASP.NET Core Identity for the user store but issues your own signed JWT.

Are Identity API endpoints production-ready?

Yes, for the scenarios they target. The underlying ASP.NET Core Identity is mature and the endpoints are maintained by the framework team. The limitation is scope, not stability: they fit single-app, first-party authentication well, and become a poor fit once you need cross-service tokens, social login, or endpoint customization. Match them to the right use case and they are production-ready.

What is the difference between cookies and tokens in Identity API endpoints?

When you call AddIdentityApiEndpoints both are enabled. Passing useCookies=true to /login returns an authentication cookie the browser carries automatically; omitting it returns an opaque bearer token in the response body. Microsoft recommends cookies for browser-based apps because the browser handles them securely without exposing them to JavaScript, and reserves tokens for clients that cannot use cookies, such as native mobile apps.

Coming soon
Draft

Custom User Management in ASP.NET Core Web API (.NET 10)

The custom layer that picks up where these endpoints stop - a custom user model, your own registration, and admin endpoints to list, role-manage, and lock users.

Read next

JWT Authentication in ASP.NET Core

Build token-based auth from scratch - the control-everything path and the TokenService used in the escape hatch above.

Read next

Refresh Tokens in ASP.NET Core

Add long-lived sessions to custom JWT auth, the way MapIdentityApi gives you /refresh for free.

Read next

Role-Based Authorization in ASP.NET Core

What you bolt on after authentication - and why opaque tokens make role claims awkward.

Read next

Permission-Based Authorization in ASP.NET Core

The next level of access control once roles are not granular enough.

Read next

API Key Authentication in ASP.NET Core

A different auth scheme for service-to-service and machine clients.

Read next

Rate Limiting in ASP.NET Core

Protect the public /register and /login endpoints from abuse.

Read next

Problem Details in ASP.NET Core

The RFC 9457 error format the Identity endpoints already return on validation failures.

Read next

Minimal APIs in ASP.NET Core

The endpoint style MapIdentityApi is built on.

Summary

Identity API endpoints are one of the best “fast path” features in modern ASP.NET Core - when you fit their scope. One MapIdentityApi() call hands you a complete first-party authentication surface, and for a SPA or mobile app talking to its own API, that is exactly the right amount of code. The trap is treating them as a general-purpose auth system. The opaque token, the fixed /register body, and the absence of social login are not bugs to work around; they are the boundary of what these endpoints are for.

So make the call deliberately. If the app will stay first-party and self-contained, use the endpoints and move on to building features. If you can see real JWTs, multiple services, or social login on the horizon, keep ASP.NET Core Identity for the user store and issue your own tokens from day one. Both paths are short. Only one of them backs you into a corner.

Happy Coding :)

Source code Open on GitHub

Grab the source code.

Get the full implementation. Drop your email for instant access, or skip straight to GitHub.

Skip - go straight to GitHub
View all articles

What's your take?

Push back, share a war story, or ask the obvious question someone else is wondering. I read every comment.

View on GitHub

Weekly .NET tips · free

Newsletter

stay ahead in .NET

One email every Tuesday at 7 PM IST. One topic, deep. The week's articles. No filler.

Tutorials Architecture DevOps AI
Join 9,735 developers · Delivered every Tuesday
Privacy notice 30s read

Cookies, but only the useful ones.

I use cookies to understand which articles get read and which CTAs actually work. No third-party advertising trackers, ever. Read the privacy policy →