D.B
D.B

Reputation: 4289

Get claims from a WebAPI Controller - JWT Token,

I have built an application which uses JWT bearer authentication in ASP.NET Core. When authenticating I define some custom claims which i need to read in another WebAPI controller in order to execute some actions.

Any ideas How Can I achieve this?

This how my code looks like:(Code has been simplified)

public async Task<IActionResult> AuthenticateAsync([FromBody] UserModel user)
    {
        ..............

                var tokenHandler = new JwtSecurityTokenHandler();
                var key = Encoding.ASCII.GetBytes(_appSettings.Secret);
                var tokenDescriptor = new SecurityTokenDescriptor
                {
                    Subject = new ClaimsIdentity(new Claim[]
                    {
                        new Claim("userSecurityKey", userDeserialized.SecurityKey.ToString()),
                        new Claim("timeStamp",timeStamp),
                        new Claim("verificationKey",userDeserialized.VerificationKey.ToString())

                    }),
                    Expires = DateTime.UtcNow.AddDays(7),
                    SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key),
                        SecurityAlgorithms.HmacSha256Signature)
                };
                var token = tokenHandler.CreateToken(tokenDescriptor);
                var tokenString = tokenHandler.WriteToken(token);

     .................                           

    }

Another controller: (It Needs to read "verificationKey" claim.)

    [HttpGet]
    [Route("getcandidate")]
    public async Task<IActionResult> GetCandidateAsync()
    {

        try
        {
             ............    


            var verificationKey = //TODO: GET VerificationKey FROM THE TOKEN

            var verificationRecord = await service.GetVerificationRecordAsync(verificationKey);

            .................

        }
        catch (Exception)
        {
            return NotFound();
        }
    }

Upvotes: 49

Views: 166658

Answers (7)

Elijah
Elijah

Reputation: 2203

The straightforward way not found anywhere here is "FindFirstValue". I will most likely write a bunch of tutorials/blog posts on ASP.NET core once I'm done my current project. Modify the following method. I use this in my authorization controller for quick testing.

#if DEBUG
    [HttpGet]
    [Authorize(Roles = "User")]
    public string TestAuthorization() {
        var email = User.FindFirstValue(JwtRegisteredClaimNames.Email);
        return $"Your email is {email}";
    }
#endif

and my GenerateToken method

    private string GenerateToken(string email) {
        var claims = new[] { new Claim(JwtRegisteredClaimNames.Email, email), new Claim(ClaimTypes.Role, "User") };
        var token = new JwtSecurityToken(jwtIssuer, jwtAudience, claims, signingCredentials: credentials);
        return jwtSecurityTokenHandler.WriteToken(token);
    }

Upvotes: 1

Mamadmti
Mamadmti

Reputation: 71

Actually you can get any claims like this and then rewrite it on your header to use it anywhere easily

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class AuthorizeAttribute : Attribute, IAuthorizationFilter
{
    public void OnAuthorization(AuthorizationFilterContext context)
    {

        var s = context.HttpContext.Request.Headers["Authorization"];
        if (AuthenticationHeaderValue.TryParse(s, out var headerValue))
        {
            // we have a valid AuthenticationHeaderValue that has the following details:

            var scheme = headerValue.Scheme;
            var parameter = headerValue.Parameter;

            // scheme will be "Bearer"
            // parmameter will be the token itself.
            // or
            var stream = parameter;
            var handler = new JwtSecurityTokenHandler();
            var jsonToken = handler.ReadToken(stream);
            var tokenS = handler.ReadToken(stream) as JwtSecurityToken;
            context.HttpContext.Request.Headers["UserName"] = tokenS.Claims.FirstOrDefault(a=>a.Type == "UserName")?.Value;


        }

        var user = context.HttpContext.Request.Headers["Authorization"];
        if (user == string.Empty)
        {
            // not logged in
            context.Result = new JsonResult(new { message = "Unauthorized" }) { StatusCode = StatusCodes.Status401Unauthorized };
        }
    }


}

Upvotes: 2

Salah ud din khan
Salah ud din khan

Reputation: 131

One way to decode JWT, and get claim is using System.IdentityModel.Tokens

public string getJWTTokenClaim(string token, string claimName)
{
    try
    {
        var tokenHandler = new JwtSecurityTokenHandler();
        var securityToken = (JwtSecurityToken)tokenHandler.ReadToken(token);
        var claimValue = securityToken.Claims.FirstOrDefault(c => c.Type == claimName)?.Value;
        return claimValue;
    }
    catch (Exception)
    {
        //TODO: Logger.Error
        return null;
    }
}

Upvotes: 13

In any controller from net core 2 that has gone through the authorize with the JwtBearerDefaults scheme, you can use:

 [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
 public ActionResult Index()
    {
        var user = User.FindFirst("Name").Value;
        //or if u want the list of claims
        var claims = User.Claims;

        return View();
    }

Upvotes: 16

avg_bloke
avg_bloke

Reputation: 214

// Cast to ClaimsIdentity.
var identity = HttpContext.User.Identity as ClaimsIdentity;

// Gets list of claims.
IEnumerable<Claim> claim = identity.Claims; 

// Gets name from claims. Generally it's an email address.
var usernameClaim = claim
    .Where(x => x.Type == ClaimTypes.Name)
    .FirstOrDefault();

// Finds user.
var userName = await _userManager
    .FindByNameAsync(usernameClaim.Value);

if (userName == null)
{
    return BadRequest();
}

// The rest of your code goes here...

Upvotes: 12

Adrian
Adrian

Reputation: 8597

You should be able to retrieve a claims like this within your controller

var identity = HttpContext.User.Identity as ClaimsIdentity;
if (identity != null)
{
    IEnumerable<Claim> claims = identity.Claims; 
    // or
    identity.FindFirst("ClaimName").Value;

}

If you wanted, you could write extension methods for the IPrincipal interface and retrieve claims using the code above, then retrieve them using (for example)

HttpContext.User.Identity.MethodName();

For completeness of the answer. To Decode the JWT token let's write a method to validate the token and extract the information.

public static ClaimsPrincipal ValidateToken(string jwtToken)
    {
        IdentityModelEventSource.ShowPII = true;

        SecurityToken validatedToken;
        TokenValidationParameters validationParameters = new TokenValidationParameters();

        validationParameters.ValidateLifetime = true;

        validationParameters.ValidAudience = _audience.ToLower();
        validationParameters.ValidIssuer = _issuer.ToLower();
        validationParameters.IssuerSigningKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(Encoding.UTF8.GetBytes(_appSettings.Secret));

        ClaimsPrincipal principal = new JwtSecurityTokenHandler().ValidateToken(jwtToken, validationParameters, out validatedToken);


        return principal;
    }

Now we can validate and extract the Claims by using:

ValidateToken(tokenString)?.FindFirst("ClaimName")?.Value

You should note that the ValidateToken method will return null value if the validation fails.

Upvotes: 101

GBU
GBU

Reputation: 324

There are a few JWT implementations for .NET Framework. If you use System.IdentityModel.Tokens.Jwt, when you validate the token you get a System.Security.Claims.ClaimsPrincipal that stores the token's claims in its "Claims" property. So you can get the token's claims as follows:

        string token = // ... read the token
        JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();
        TokenValidationParameters validationParameters = ...;
        SecurityToken securityToken;
        IPrincipal principal;
        try
        {
            // token validation
            principal = tokenHandler.ValidateToken(token, validationParameters, out securityToken);
            // Reading the "verificationKey" claim value:
            var vk = principal.Claims.SingleOrDefault(c => c.Type == "verificationKey").Value; 
        }
        catch
        {
            principal = null; // token validation error
        }

Now where do you place this code? My choice was to implement the token validation as an authorization filter attribute derived from AuthorizationFilterAttribute. If you decorate a controller with the attribute, its OnAuthorization method is executed before every call to the controller's endpoints. You place the above code on the OnAuthorization method, and store the principal returned by the token validation on HttpContext.Current.User, that is also accessible on any endpoint on your API. http://blogs.quovantis.com/json-web-token-jwt-with-web-api/ is a nice sample of this implementation.

Upvotes: 2

Related Questions