Claims and ClaimsPrincipal
“What is a claim, and what is a ClaimsPrincipal in ASP.NET Core?”
How the API knows who is calling: a list of small facts about the user, rebuilt from the token on every request.
See it
1/8A request arrives with a token. Inside: claims about Priya, a credit officer at dealer D-204.
In plain words
When someone signs in, the sign-in service (at our clients, Entra ID, Microsoft's sign-in service) gives their app an access token: a signed card the app shows on every call to the API. The signature proves nobody edited the claims after the service wrote them (). The token carries small facts about the person: their id, their name, their roles, which dealer they work for. Each fact is a claim: a name and a value, like role = CreditOfficer or dealer_id = D-204. Two jobs use claims. Authentication means proving who you are: on every request, the authentication middleware checks the token and copies its claims into an object called a , the signed-in user as .NET sees them. Authorization means deciding what that user may do: roles and policies read the claims (a policy is a named rule, see ). You find the principal at , or just inside a controller. Your code asks it questions: what is your name, are you in this role, which dealer are you from. The API does not look the user up in a database to answer: everything it knows is in those claims. Inside the principal sits a : the claims that came from one source (here, one token) plus a label for how they were proven (its authentication type; for a token, the JWT handler inside the middleware sets it). The identity counts as signed in only when it has that label. The principal is rebuilt from the token on every request. Nothing is kept between requests, unlike a login session.
- A claim is one name-value fact about the user, issued by a trusted party: the user id, name, roles, a dealer id.
- ASP.NET Core represents the user as a . The authentication middleware builds it on every request from the token, and it sits at . It holds one or more objects, each with its own claims and a label for how it was proven.
- Authorization then reads those claims:
[Authorize(Roles = ...)]checks role claims, a policy, which is a named rule, can check any claim, and my own code reads . is true only when the identity has that proof label. - Claims are only as fresh as the token. A removed role stays until the token expires, which is one reason access tokens are short-lived.
In the lending API
A controller that reads the caller's claims. Tap Next line to walk it.
Lending.sln · where this file sits
- src/Api/Controllers/
What they ask next
Interviewers check that you can explain every line. Tap a question to open it.
Where do the claims come from?
From whoever issued the token. At our clients that is : an admin gives a person an app role, and the next token they get carries it as a role claim. The API only reads them. The JWT handler may also rename short claim names to longer .NET names on the way in; the shows it.
Can the API add its own claims?
Yes, with
IClaimsTransformation: a class whose method runs after authentication and can add claims, for example a permission loaded from a cache. It can run more than once per request, so it must be idempotent (it must not add a claim twice), fast, and must not call the database each time.Why does a principal hold a list of identities, not one?
A user can be proven more than one way at once, say a cookie and a client certificate. Each way gives its own identity. Most APIs have exactly one.
Why is null when the token has a name?
reads the claim type set as
NameClaimType, which by default is the long .NET name, not the token's shortname. Either setNameClaimType = "name"in the token validation settings, or read .
Traps
- Don't say
Take the dealer id from the request body or the URL.SayTake it from the claims. The token is signed, so the caller can't change it; the body is whatever they typed. - Don't say
A role change shows up at once.SayOnly in the next token. Until the current one expires, the old claims stand.