How to get current user in .NET Core Web API (from JWT Token)

After many problems (and many tuturials, manuals, etc.), I was able to configure a small .NET REST API Web site with an Auth Controller issuing JWT tokens when the username and password are saved.

The token stores the user ID as a subitem.

I also managed to configure the web API to validate these tokens when the method uses Authorize annotation.

  app.UseJwtBearerAuthentication (...) 

Now my question is: How can I read the user ID (stored in the application) in my controllers (in the web API)?

Basically this question ( How to get current user in ASP.NET Core ), but I need an answer for web api. And I do not have UserManager. Therefore, I need to read the subject suit somewhere.

+28
source share
6 answers

You can use this method:

var email = User.FindFirst("sub")?.Value; 

In my case, I use email as a unique value

+17
source

The accepted answer did not work for me. I'm not sure if this was due to the fact that I was using .NET Core 2.0 or something else, but it looks like the framework matches the subject's requirement with the NameIdentifier statement. So, the following worked for me:

 string userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value; 

Note that this assumes that Subject sub Claim is set to JWT, and its value is the user ID.

By default, the JWT authentication handler in .NET maps the System.Security.Claims.ClaimTypes.NameIdentifier JWT access token claim to the System.Security.Claims.ClaimTypes.NameIdentifier claim type. [A source]

There is also a discussion thread on GitHub where they conclude that this behavior is confusing.

+35
source

If you use Name to store the ID here:

 var tokenDescriptor = new SecurityTokenDescriptor { Subject = new ClaimsIdentity(new Claim[] { new Claim(ClaimTypes.Name, user.Id.ToString()) }), Expires = DateTime.UtcNow.AddDays(7), SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature) }; 

In each controller method, you can download the current user ID:

 var claimsIdentity = this.User.Identity as ClaimsIdentity; var userId = claimsIdentity.FindFirst(ClaimTypes.Name)?.Value; 
+10
source

It seems like many people are looking at this question, so I would like to share some additional information that I learned since I asked the question a while ago. This makes some things more understandable (at least for me) and has not been as obvious (for me, as a .NET newbie).

As Markus Heglund noted in the comments:

It should be the same for the "web api". In ASP.NET, Core Mvc and Web Api are combined to use one controller.

This is definitely true and absolutely correct.


Because it's all the same for .NET and .NET Core.

Back than I was new to .NET Core and actually the whole .NET world. An important missing piece of information was that in .NET and .NET Core all authentication can be truncated to the System.Security.Claims namespace with its ClaimsIdentity, ClaimsPrinciple and Claims.Properties. And therefore, it is used in both types of .NET Core controllers (API and MVC or Razor or ...) and is available through HttpContext.User .

Important Note: All tutorials are skipped.

Therefore, if you start to do something with JWT tokens in .NET, be sure to also make sure that ClaimsIdentity , ClaimsPrinciple and Claim.Properties are reliable . It is all about that. Now you know that. This was pointed out by Goeringer in one of the comments.


ALL claims-based authentication intermediaries (if implemented correctly) populate HttpContext.User claims received during authentication.

As far as I understand, now this means that you can safely trust the values โ€‹โ€‹in HttpContext.User . But wait a bit to understand what to consider when choosing middleware. Many different middleware authentication programs are already available (in addition to .UseJwtAuthentication() ).

With small custom extension methods, you can now get the current user ID (more precisely, subject approval)

  public static string SubjectId(this ClaimsPrincipal user) { return user?.Claims?.FirstOrDefault(c => c.Type.Equals("sub", StringComparison.OrdinalIgnoreCase))?.Value; } 

Or do you use the version in response to Ateik .


BUT WAITING : there is one strange thing

The next thing that confused me was that: according to the OpenID Connect specification, I was looking for a โ€œsubโ€ application (current user), but could not find it. Like Honza Kalfus could not do in his answer.

What for?

Because Microsoft "sometimes" is "slightly" different. Or at least they do a bit more (and unexpected) things. For example, the official Microsoft JWT Bearer authentication middleware mentioned in the original question. Microsoft decided to convert the claims (claim names) into all of their official authentication middleware (for reasons of compatibility, I donโ€™t know in more detail).

You will not find a โ€œsubordinateโ€ application (although this is the only application specified by OpenID Connect). Because he turned into these trendy ClaimTypes . This is not all bad, it allows you to add mappings if you need to match different claims with a unique internal name.

Either you adhere to the Microsoft naming convention (and you should keep this in mind when you add / use non-Microsoft middleware), or you will learn how to change the assertion compliance for Microsoft middleware.

In the case of JwtBearerAuthentication, this is done (do it early in StartUp or at least before adding middleware):

 JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); 

If you want to stick with Microsoft's naming of subject matter claims (don't beat me, I'm not sure right now if the name is the correct match):

  public static string SubjectId(this ClaimsPrincipal user) { return user?.Claims?.FirstOrDefault(c => c.Type.Equals(ClaimTypes.NameIdentifier, StringComparison.OrdinalIgnoreCase))?.Value; } 

Note that other answers use the more advanced and more convenient FindFirst method. Although my code examples show this without them, you can go with them.

Thus, all your claims are stored and accessible (through one or another name) in HttpContext.User .


But where is my token?

I do not know for other middleware, but Authentication on JWT media allows you to save a token for each request. But it needs to be activated (in StartUp.ConfigureServices(... ).

 services .AddAuthentication("Bearer") .AddJwtBearer("Bearer", options => options.SaveToken = true); 

The actual token (in all its mysterious form) as a string (or zero) can be accessed through

 HttpContext.GetTokenAsync("Bearer", "access_token") 

There was an older version of this method (this works for me in .NET Core 2.2 without an outdated warning).

If you need to parse and extract values โ€‹โ€‹from this line, the question of how to decode the JWT token can help.


Well, I hope this resume helps you.

+5
source

You can do this using.

User.Identity.Name

+2
source

I used HttpContext and it works well:

 var email = string.Empty; if (HttpContext.User.Identity is ClaimsIdentity identity) { email = identity.FindFirst(ClaimTypes.Name).Value; } 
+2
source

Source: https://habr.com/ru/post/1271632/


All Articles