C# and ASP.NET Core 6 : authentication and user details in "session"

Viewed 1167

I'm going to get so many "okay grandpa" comments for this one.

I've read a dozen articles and every SO question I could find on this subject.

I must have been away too long or missed something completely, because I swear that user authentication used to be very simple. I seem to recall built-in methods and a session on the server simply knowing who the user was via a cookie or similar, with the ability to store information "in session". I don't recall even setting up authentication in years past, it was just built-in to new applications.

Instead, the most succinct guide I could find is very involved. I think I need a token authorization/authentication setup because there may be consumers (like apps) who don't have a typical cookie pattern these days. In my head, the token works like a cookie except it's manually held on the user end and passed via header with each request?

To its credit, the guide worked, at least for logging in and correctly utilizing the simple Authorize attribute in controllers. However, User.Identity.Name is always empty, even when User.Identity.IsAuthenticated is true, which is perplexing.

How I think auth is working:

  • User request hits API with username/password
  • Service checks the combination, and returns an encrypted JWT to the user
  • The user sends the JWT back with every request
  • The server decrypts this JWT to identify the user - this is probably where I'm wrong

So here is where my question comes in:

I need more data about the user, like access to the entire UserModel with every request, but I don't want to go to the database to find it every time. This is where I think there should just be a session object in memory, but that doesn't appear to be the case with token authentication.


TL;DR:

Where do I put user-specific, short-term ("session") information for consumption in future requests where a user is identified with a JWT in the Authorization header instead of a cookie?

  • Session state isn't right, because it's hard-wired to a cookie
  • HttpContext.Items aren't right, because it's just for the one request
  • Cache storage isn't right, because it's not user/session specific. I could potentially create a session-like user-keyed storage here but that seems way, way over-engineered for this.
  • Basically anything where I'm passing all the data (not just a user identifier) to the client then relying on the client to pass it back seems wrong? But feel free to correct me.
1 Answers

The server decrypts this JWT to identify the user This is probably where I'm wrong

The JWT token is not encrypted, its signed so you can't alter it. You can open it if you look at jwt.io for example.

Where do I put user-specific, short-term ("session") information for consumption in future requests where a user is identified with a JWT in the Authorization header instead of a cookie?

You put it in the principle claims of the token. In the guide you linked it wrote:

  var claims = new List<Claim>
  {
       new Claim(JwtRegisteredClaimNames.NameId, user.UserName)
  };

So you add whatever you want to the claims to store it on the token and later you can access this data via:

var claim = _contextAccessor.HttpContext.User?.Claims.FirstOrDefault(d =>
                    d.Type == ClaimTypes.NameIdentifier);

You also can't use any of these other examples that you listed like HttpContext.Items because those are not signed. If the token is altered in any way the system identifies this and returns a 401

Related