Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generating a JWT token using AuthenticateAsync

I am trying to login using ClaimsPrincipal and then fetch a JWT in .net core 2.0. With my current code, I get the error from the result of the SignInAsync function: "No IAuthenticationSignInHandler is configured to handle sign in for the scheme: Bearer"

Here is the controller I am currently using:

[Route("Login/{username}")]
public async Task<IActionResult> Login(string username)
{
    var userClaims = new List<Claim>
    {
        new Claim(ClaimTypes.Name, username)
    };
    var principal = new ClaimsPrincipal(new ClaimsIdentity(userClaims));
    var sign = HttpContext.SignInAsync(principal);
    await sign;
    var res = await HttpContext.AuthenticateAsync();
    var token = await HttpContext.GetTokenAsync("access_token");
    return Json(token);
}

The login portion was tested and works well with cookies. However when I use the following code with JwtBearerDefaults.AuthenticationScheme in my startup.cs:

services.AddAuthentication(config => {
    config.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    config.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(config =>
{
    config.TokenValidationParameters = Token.tokenValidationParameters;
    config.RequireHttpsMetadata = false;
    config.SaveToken = true;
});

I get the error from the result of the SignInAsync function: "No IAuthenticationSignInHandler is configured to handle sign in for the scheme: Bearer"

My Token class was created with the help of a code I found online (at JWT on .NET Core 2.0) and is defined as follows:

public static class Token
{

    public static TokenValidationParameters tokenValidationParameters {
        get
        {

            return new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = GetSignInKey(),
                ValidateIssuer = true,
                ValidIssuer = GetIssuer(),
                ValidateAudience = true,
                ValidAudience = GetAudience(),
                ValidateLifetime = true,
                ClockSkew = TimeSpan.Zero
            };
        }
    }

    static private SymmetricSecurityKey GetSignInKey()
    {
        const string secretKey = "very_long_very_secret_secret";
        var signingKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey));

        return signingKey;
    }

    static private string GetIssuer()
    {
        return "issuer";
    }

    static private string GetAudience()
    {
        return "audience";
    }

}
like image 377
Neville Nazerane Avatar asked Jun 07 '26 15:06

Neville Nazerane


2 Answers

If I understand it correctly from looking at the source code for JwtBearerHandler, it does not implement IAuthenticationSignInHandler, which is why you are getting this error. Call to SignInAsync is designed to persist authentication information, such as created auth cookie which, for instance, is exactly what CookieAuthenticationHandler does. But for JWT there is no single well-known place to store the token, hence no reason to call SignInAsync at all. Instead of that, grab the token and pass it back to the browser. Assuming you are redirecting, you can tuck it into a query string. Assuming browser application is an SPA (i.e. Angular-based) and you need tokens for AJAX calls, you should store token in the SPA and send it with every API request. There are some good tutorials on how to use JWT with SPAs of different types, such as this: https://medium.com/beautiful-angular/angular-2-and-jwt-authentication-d30c21a2f24f

Keep in mind that JwtBearerHandler expects to find Authentication header with Bearer in it, so if your AJAX calls are placing token in query string, you will need to supply JwtBearerEvents.OnMessageReceived implementation that will take token from query string and put it in the header.

like image 171
iTolik Avatar answered Jun 09 '26 13:06

iTolik


A signed token can be created using the JwtSecurityTokenHandler.

var handler = new JwtSecurityTokenHandler();
var jwt = handler.CreateJwtSecurityToken(new SecurityTokenDescriptor
{
     Expires = DateTime.UtcNow.Add(Expiary),
     Subject = new ClaimsIdentity(claims, "local"),
     SigningCredentials = new SigningCredentials(SigningKey, SecurityAlgorithms.HmacSha256)
});
return handler.WriteToken(jwt);
like image 38
Neville Nazerane Avatar answered Jun 09 '26 15:06

Neville Nazerane