5

Using both Cookie Authentication Middleware and JWT Authentication Middleware. When I sign in the user I create custom Claims and attach those to the cookie based identity. I also get a jwt token from an external source, and that has its own claims (I use this token to access external resources). My controller class looks something like this when enabling Authentication

[Authorize(AuthenticationSchemes = AuthSchemes)]
public class MixedController : Controller
// Requires the following imports:
// using Microsoft.AspNetCore.Authentication.Cookies;
// using Microsoft.AspNetCore.Authentication.JwtBearer;
private const string AuthSchemes =
    CookieAuthenticationDefaults.AuthenticationScheme + "," +
    JwtBearerDefaults.AuthenticationScheme;

Based on the code snippet above, if either, Cookie or JWT auth is successful the request is deemed Authenticated. My requirement is to reject the request if either Cookie Auth or JWT auth fails. Using just one schema is not a good option for my case. If my cookie is valid but my token has expired I would like to fail the request on grounds of "not being authenticated". How can I do that?

Jonathan
  • 73
  • 2
  • 8

2 Answers2

6

Use policy based authentication. There you can check if current ClaimsPrincipal (context.User) has 2 Identities, 1 from each successfully passed authentication scheme. Configure policy

services.AddAuthorization(options =>
{
    options.AddPolicy("RequireAllSchemes", policy =>
    {
        policy.AddAuthenticationSchemes(CookieAuthenticationDefaults.AuthenticationScheme);
        policy.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme);
        policy.RequireAuthenticatedUser();
        policy.RequireAssertion(context =>
        {
            return context.User.Identities.Count() == 2;
        });
    });
});

Specify authorization policy for controller

[Authorize(Policy = "RequireAllSchemes")]
public class MixedController : Controller
Alexander
  • 9,104
  • 1
  • 17
  • 41
  • Thanks Alexander. I did give this approach a try. Unfortunately the behavior was the same as when I used the comma separated Scheme. Which surprises me, because I was under the impression that when the [Authorize] filter fails it short-circuits the mvc filter pipeline. In my case when I have an invalid jwt (expired) and a valid Cookie - I still get access to the route. – Jonathan Feb 18 '19 at 21:40
  • @Jonathan I've updated (and this time tested) my answer. Please try it out. – Alexander Feb 20 '19 at 22:40
  • @Jonathan Also you need to implement expiration validation for jwt because it might be considered valid and pass authentication. – Alexander Feb 20 '19 at 22:52
  • Thank you very much. This worked for me. Yes, I do have expiration validation in place. I also like how you have encapsulated your solution within a Policy - it really helps with re-usability. – Jonathan Feb 22 '19 at 23:20
2

An alternative approach

   services.AddAuthorization(options => {
                    options.AddPolicy(Policies.Users, policy => {
                        policy.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme); 
                        policy.AddAuthenticationSchemes(CookieAuthenticationDefaults.AuthenticationScheme)
                        policy.RequireAuthenticatedUser(); 
                        policy.RequireClaim(JwtClaimTypes.Scope, ResourceNames.IdentityUsers);
                        policy.RequireClaim(BasicClaimTypes.Admin, bool.TrueString.ToLower());
                    });});
Pan Markosian
  • 101
  • 14