4

Is there a way to use JWT bearer authentication AND a custom authentication method in .net core? I want all actions to default to JWT, except in a few cases where I want to use a custom authentication header.

1

1 Answer 1

7

I finally figured out how to do it. This example uses JWT authentication by default and custom authentication in certain rare cases. Please note, from what I've read, Microsoft seems to discourage writing your own auth. Please use at your own risk.

First, add this code to the startup.cs ConfigureServices method to ensure that authentication gets applied globally.

services.AddMvc(options => 
    {
        var policy = new AuthorizationPolicyBuilder()
            .RequireAuthenticatedUser()
            .Build();
        options.Filters.Add(new AuthorizeFilter(policy));
    })

Then, add this to configure the schemes you wish to use (in our case JWT and Custom).

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    // Jwt Authentication
    .AddJwtBearer(options =>
    {
        options.Audience = ".......";
        options.Authority = "https://cognito-idp.us-east-1.amazonaws.com/us-east-1_...";
    })
    // Custom auth
    .AddScheme<CustomAuthOptions, 
        CustomAuthHandler>(CustomAuthOptions.DefaultScheme, options => { });

Next create a class to hold your custom authentication options:

public class CustomAuthOptions : AuthenticationSchemeOptions
{
    public const string Scheme = "custom auth";
    public const string CustomAuthType = "custom auth type";
}

Finally, add an authentication handler to implement the custom authentication logic.

public class CustomAuthHandler : AuthenticationHandler<CustomAuthOptions>
{
    public CustomAuthHandler(
        IOptionsMonitor<CustomAuthOptions> options, 
        ILoggerFactory logger, 
        UrlEncoder encoder, 
        ISystemClock clock) : base(options, logger, encoder, clock)
    {
    }

    protected override Task<AuthenticateResult> HandleAuthenticateAsync()
    {
        // Auth logic goes here
        if (!Request.Headers....) 
        {
            return Task.FromResult(AuthenticateResult.Fail("Authentication Failed."));
        }

        // Create authenticated user
        ClaimsPrincipal principal = .... ;

        List<ClaimsIdentity> identities = 
            new List<ClaimsIdentity> {
                new ClaimsIdentity(CustomAuthOptions.CustomAuthType)};

        AuthenticationTicket ticket = 
            new AuthenticationTicket(
                new ClaimsPrincipal(identities), CustomAuthOptions.Scheme);

        return Task.FromResult(AuthenticateResult.Success(ticket));
    }
}

Finally, to tie it all together, add an authorize attribute to the actions you wish to use custom authorization on.

[HttpGet]
[Authorize(AuthenticationSchemes = CustomAuthOptions.Scheme)]
public HttpResponseMessage Get()
{
    ....
}

Now JWT authentication will automatically get applied to all actions, and custom authentication will get added to only the actions with the Authorize attribute set to the custom scheme.

I hope this helps someone.

Sign up to request clarification or add additional context in comments.

2 Comments

for instance, basic auth: jasonwatmore.com/post/2018/09/08/…
This naswer is extermely helpful: "Use multiple JWT Bearer Authentication" stackoverflow.com/a/49706390/218651

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.