skip to Main Content

im using JWT to Authentication, and I’m storing it in Cookies. I want to use HttpContext.SignInAsync to login, I saw a lot of example with basic Cookie Auth, but not with JWT.

Here is my Startup.cs

 services.AddTransient<IUserRepository, UserRepository>();
        services.AddTransient<ITokenService, TokenService>();
        IdentityModelEventSource.ShowPII = true;
        services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>
        {

            options.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidateLifetime = true,
                ValidateIssuerSigningKey = true,
                ValidIssuer = Configuration["Jwt:Issuer"],
                ValidAudience = Configuration["Jwt:Issuer"],
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]))
            };
            options.SaveToken = true;
            options.Events = new JwtBearerEvents();
            options.Events.OnMessageReceived = context =>
            {

                if (context.Request.Cookies.ContainsKey("X-Access-Token"))
                {
                    context.Token = context.Request.Cookies["X-Access-Token"];
                }

                return Task.CompletedTask;
            };
        })
          .AddCookie(options =>
          {
              options.Cookie.SameSite = SameSiteMode.Strict;
              options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
              options.Cookie.IsEssential = true;

          });

Here is my Login (Its currently working, but it would be bettern with SignInAsync

public IActionResult Login(LoginModel loginModel, string returnUrl)
        {
            if (string.IsNullOrEmpty(loginModel.UserName) || string.IsNullOrEmpty(loginModel.Password))
            {
            ViewBag.Message = "Nem lehet üres";
            return View("Index",loginModel);
            }

            IActionResult response = Unauthorized();
            var validUser = GetUser(loginModel);

            if (validUser != null)
            {
                generatedToken = _tokenService.BuildToken(_config["Jwt:Key"].ToString(), _config["Jwt:Issuer"].ToString(),
                validUser);

                if (generatedToken != null)
                {
                    Response.Cookies.Append("X-Access-Token", generatedToken, new CookieOptions() { HttpOnly = true, SameSite = SameSiteMode.Strict, Secure=true });
                    Response.Cookies.Append("X-Username", loginModel.UserName, new CookieOptions() { HttpOnly = true, SameSite = SameSiteMode.Strict, Secure=true });
                    //Response.Cookies.Append("X-Refresh-Token", user.RefreshToken, new CookieOptions() { HttpOnly = true, SameSite = SameSiteMode.Strict });
                   // HttpContext.Session.SetString("Token", generatedToken);
                if (returnUrl != null)
                {
                    return Redirect(returnUrl);
                }
                else
                {
                    return RedirectToAction("MainWindow");
                }
            }
                else
                {
                ViewBag.Message = "Nem jo token";
                return View("Index", loginModel);
            }
            }
            else
            {
            ViewBag.Message = "Nem jó user";
            return View("Index", loginModel);
        }
        }

And here is my Token service:

public class TokenService : ITokenService
{
    private const double EXPIRY_DURATION_MINUTES = 30;

    public string BuildToken(string key, string issuer, User user)
    {
        var claims = new[] {
        new Claim(ClaimTypes.Name, user.Name),
        new Claim(ClaimTypes.Role, user.Role),
        new Claim(ClaimTypes.NameIdentifier,
        Guid.NewGuid().ToString())
        };

        var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key));
        var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256Signature);
        var tokenDescriptor = new JwtSecurityToken(issuer, issuer, claims,
            expires: DateTime.Now.AddMinutes(EXPIRY_DURATION_MINUTES), signingCredentials: credentials);
        return new JwtSecurityTokenHandler().WriteToken(tokenDescriptor);
    }
    public bool IsTokenValid(string key, string issuer, string token)
    {
        var mySecret = Encoding.UTF8.GetBytes(key);
        var mySecurityKey = new SymmetricSecurityKey(mySecret);

        var tokenHandler = new JwtSecurityTokenHandler();
        try
        {
            tokenHandler.ValidateToken(token, new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidIssuer = issuer,
                ValidAudience = issuer,
                IssuerSigningKey = mySecurityKey,
            }, out SecurityToken validatedToken);
        }
        catch
        {
            return false;
        }
        return true;
    }
}

Edit 1 – Added the question

How can I implement HttpContext.SignInAsync in this situation?

3

Answers


  1. My startup like below:

     services.AddAuthentication(options =>
                {
                    // custom scheme defined in .AddPolicyScheme() below
                    options.DefaultScheme = "JWT_OR_COOKIE";
                    options.DefaultChallengeScheme = "JWT_OR_COOKIE";
                })
               // Adding Jwt Bearer  
               .AddJwtBearer(options =>
               {
                  ....//do your staff
               }).AddCookie("Cookies", options =>
               {
                   options.LoginPath = "/account/login";
                   options.ExpireTimeSpan = TimeSpan.FromDays(1);
               }).AddPolicyScheme("JWT_OR_COOKIE", "JWT_OR_COOKIE", options =>
               {
                   // runs on each request
                   options.ForwardDefaultSelector = context =>
                   {
                       // filter by auth type
                       string authorization = context.Request.Headers[HeaderNames.Authorization];
                       if (!string.IsNullOrEmpty(authorization) && authorization.StartsWith("Bearer "))
                           return "Bearer";
    
                       // otherwise always check for cookie auth
                       return "Cookies";
                   };
                   });
    

    Add more code:

    Some code in this answer

    In Login post method
    I add below into the claims

    new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
    

    And my token generated as below, when you login , you will get token.

    var authSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["JWT:Secret"]));
    
                        var token = new JwtSecurityToken(
                            issuer: _configuration["JWT:ValidIssuer"],
                            audience: _configuration["JWT:ValidAudience"],
                            expires: DateTime.Now.AddHours(3),
                            claims: claims,
                            signingCredentials: new SigningCredentials(authSigningKey, SecurityAlgorithms.HmacSha256)
                            );
    
                        return Ok(new
                    {
                        token = new JwtSecurityTokenHandler().WriteToken(token),
                        expiration = token.ValidTo
                    });
    

    Result:

    enter image description here

    Login or Signup to reply.
  2. Do you mean you want read claims from jwt and ceate a new ticket for cookie authentication as below:

    var jwtsecuritytoken = new JwtSecurityTokenHandler().ReadToken(token) as JwtSecurityToken;
                        var username = jwtsecuritytoken.Claims.FirstOrDefault(m => m.Type == ClaimTypes.Name).Value;
                         .......
                         //add other logic
                        .........
                            var claims = new Claim[]
                            {
                            new Claim(ClaimTypes.Name, username),
                             ..........
                             };
                            var claimsIdentity = new ClaimsIdentity(claims);
                            await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity));
                        }
    
    Login or Signup to reply.
  3. just change authentication like below

     services.AddAuthentication(options =>
                {
                    options.DefaultAuthenticateScheme = "JwtBearerDefaults.AuthenticationScheme";
                    options.DefaultChallengeScheme = "JwtBearerDefaults.AuthenticationScheme";
                    options.DefaultSignInScheme = "JwtBearerDefaults.AuthenticationScheme";
             
                })
    

    authentication middleware do signin context automaticly

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search