Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extract values from HttpContext.User.Claims

I'm trying to extract an email address from HttpContext.User.Claims and I'd like to ask for help to come up with a better way to code this (maybe using LINQ?)

The way I'm doing it now seems very hacky.

var userClaimsList = HttpContext.User.Claims.ToList();

// List is of varying length but email is always 3rd from the bottom.
int emailPosition = userClaimsList.Count()-3; 
string searchString = "preferred_username: "; 

// dirtyEmail = "preferred_username: xyz@emailcom"
string dirtyEmail = userClaimsList[emailPosition].ToString();
string cleanEmail = dirtyEmail.Replace(searchString, "").ToLower().Trim();

I've tried the LINQ solutions recommended in another post but receive the error Operator == cannot be applied to operands of type 'Claim' and 'string'.

like image 628
forcequitIO Avatar asked May 01 '18 17:05

forcequitIO


People also ask

What is HttpContext user?

The User property provides programmatic access to the properties and methods of the IPrincipal interface. Because ASP.NET pages contain a default reference to the System. Web namespace (which contains the HttpContext class), you can reference the members of HttpContext on an .

What is System Security claims ClaimsPrincipal?

ClaimsPrincipal exposes a collection of identities, each of which is a ClaimsIdentity. In the common case, this collection, which is accessed through the Identities property, will only have a single element.


2 Answers

Claim objects are a bit more than just a simple string, and what you are looking at in the userClaimsList is a list of these claim objects.

Claims are mostly pairs of a claim type and a claim value, and when you look for certain information about a user, you should use the claim type to identity the user property you are looking for.

What you do in your code is assume that the claim you are looking for is the third to last, which by itself is already a dangerous assumption since you cannot be sure that this will always be the case: claims are generally considered unordered and you should look for them by type. And once you get the type, you then .ToString() it, which essentially reduces all the information the Claim type has down to a single string of the format claimType: claimValue. You can use that, but it’s really inefficient when the object itself as a much better way of accessing the claim value.

Since you are looking for the prefix "preferred_username: ", I assume that preferred_username is the claim type you are looking for. In that case, you could look up that claim like this:

var claim = HttpContext.User.Claims.First(c => c.Type == "preferred_username");
var emailAddress = claim.Value;

The use of First will throw an exception if a claim with that type was not found. If you don’t want that, you can use FirstOrDefault and then check whether claim is null.

There are also a few helper extensions that allow you to extract claims directly. In this case, you could use FindFirstValue on the user to get the claim value directly:

var emailAddress = HttpContext.User.FindFirstValue("preferred_username");

In case a claim with that type was not found, FindFirstValue will return null, so emailAddress could be null in this case.

like image 140
poke Avatar answered Oct 19 '22 07:10

poke


What you are doing is not only assuming something you cannot ensure, but also much harder than needed:

// note: HttpContext.User == User
var cleanEmail = User.FindFirst(ClaimTypes.Email)?.Value;

If the data is not on the email claim type, check the corresponding type and use that instead. In your case, it seems that it should be preferred_username:

var cleanEmail = User.FindFirst("preferred_username")?.Value;
like image 44
Camilo Terevinto Avatar answered Oct 19 '22 08:10

Camilo Terevinto