Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make JWT token authorization optional in controller methods

I use JWT tokens in my ASP.NET Core 2 web application

If the JWT token fails I still want the controller method to be hit but the ASP.NET Identity User object will just be null. Currently the controller method won't get entered if authentication fails so I can't apply logic inside the method to deal with non authenticated users which I want to deal with as guests instead of blocking them.

My code:

Startup.cs

    public void ConfigureServices(IServiceCollection services)
    {

        services.AddAuthentication()
            .AddJwtBearer(cfg =>
            {
                cfg.TokenValidationParameters = new TokenValidationParameters()
                {
                    ValidIssuer = _config["Tokens:Issuer"],
                    ValidAudience = _config["Tokens:Audience"],
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Tokens:Key"]))
                };

            });

When a user logs in

   private IActionResult CreateToken(ApplicationUser user, IList<string> roles)
    {
        var claims = new List<Claim>
        {
          new Claim(JwtRegisteredClaimNames.Sub, user.Id.ToString()),
          new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
          new Claim(JwtRegisteredClaimNames.UniqueName, user.UserName)
        };



        var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Tokens:Key"]));

        var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

        var token = new JwtSecurityToken(
          _config["Tokens:Issuer"],
          _config["Tokens:Audience"],
          claims.ToArray(),
         expires: DateTime.Now.AddMinutes(60),
          signingCredentials: creds);

        var results = new
        {
            token = new JwtSecurityTokenHandler().WriteToken(token),
            expiration = token.ValidTo,
        };

        return Created("", results);

I make sure after authenticated the various API calls pass the JWT token.

In my Controller I make use of an Authorize attribute

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
 public class MyController : Controller
{

This allows me to capture the logged in user with the following code for the various API calls

 var loggedInUser = User.Identity.Name;

If I remove the authorize attribute then User.Identity.Name will always be null even if the user is authenticated.

How do I use the authorize attribute but still allow the controller method to be entered if the token is not valid? I want to use the same method for both Authorized and non Authorized users to be entered. I will then use the User.Identity.Name to determine if they are not authenticated and have guest user logic inside the method for them.

like image 329
dfmetro Avatar asked Feb 08 '18 13:02

dfmetro


People also ask

How do you add the JWT token for all the requests without duplicating for each request?

Go to "Authorization" tab, select "Bearer Token" authorization type and for value just enter {{jwt-token}} . That's it. Now you have to execute login request only once and JWT token will automatically be used in all other request.

How do you handle authorization with JWT?

To authenticate a user, a client application must send a JSON Web Token (JWT) in the authorization header of the HTTP request to your backend API. API Gateway validates the token on behalf of your API, so you don't have to add any code in your API to process the authentication.

Under Which method should a policy be registered for it to be a part of authorization service?

First, you have to register your policy in the ConfigureServices() method of the Startup class, as part of the authorization service configuration.


2 Answers

It's actually easier than you might expect. You can just use both Authorize and AllowAnonymous, like so:

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[AllowAnonymous]
public class MyController : Controller

If authorization was successful, you'll have an authenticated User (User.Identity.IsAuthenticated = true), otherwise, you will have an anonymous User.

like image 70
Kirk Larkin Avatar answered Oct 11 '22 13:10

Kirk Larkin


I'm not sure when this changed but my application is on ASP.NET Core 3.1 and without my actions/endpoints specifying that I require authorization, the authentication middleware still provides the information I require inside my ClaimsPrincipal when a valid token is provided and a blank principal when no token is specified.

like image 45
Jeremy Borg Avatar answered Oct 11 '22 13:10

Jeremy Borg