ASP.Net Core JWT Login not setting HttpContext.User.Claims











up vote
0
down vote

favorite
1












I have the following for my login code, and another method to retrieve the user ID in another call.



        // POST: /api/Account/Login
[HttpPost]
[AllowAnonymous]
public async Task<IActionResult> Login([FromBody]LoginViewModel model)
{
if (ModelState.IsValid)
{
var user = await _userManager.FindByEmailAsync(model.Email);
if (user != null)
{
if (!await _userManager.IsEmailConfirmedAsync(user))
{
ModelState.AddModelError(string.Empty,
"You must have a confirmed email to log in.");
return BadRequest(Errors.AddErrorToModelState("Email", "You must have a confirmed email to log in.", ModelState));
}
}

var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false);

if (result.Succeeded)
{
// IS THIS NEEDED? --> // HttpContext.User = await _userClaimsPrincipalFactory.CreateAsync(user);
var tokens = _antiforgery.GetAndStoreTokens(HttpContext);

var identity = _jwtFactory.GenerateClaimsIdentity(model.Email, user.Id);
_logger.LogInformation(1, "User logged in.");
var jwt = await Tokens.GenerateJwt(identity, _jwtFactory, model.Email, _jwtOptions, new JsonSerializerSettings { Formatting = Formatting.Indented });
return new OkObjectResult(jwt);
}

if (result.RequiresTwoFactor)
{
//return RedirectToAction(nameof(SendCode), new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
}

if (result.IsLockedOut)
{
string message = "User account locked out.";
_logger.LogWarning(2, message);
return BadRequest(Errors.AddErrorToModelState("Email", message, ModelState));
}

if (result.IsNotAllowed)
{
string message = "User account is not allowed to sign in.";
_logger.LogWarning(2, message);
return BadRequest(Errors.AddErrorToModelState("Email", message, ModelState));
}

return BadRequest(Errors.AddErrorToModelState("", "Sign in failed.", ModelState));
}

return BadRequest(Errors.AddErrorToModelState("", "", ModelState));
}

public string GetUserId()
{
string username = string.Empty;

ClaimsPrincipal principal = HttpContext.User as ClaimsPrincipal;

if (HttpContext.User != null)
{
var id = HttpContext.User.FindFirst(ClaimTypes.NameIdentifier);

if (id != null)
{
username = id.Value;
}
}

return username;
}


This is the code for GenerateJwt. (Are these fields standard? I see other fields being set in other code, such as in https://code-maze.com/authentication-aspnetcore-jwt-1/.)



  public static async Task<string> GenerateJwt(ClaimsIdentity identity, IJwtFactory jwtFactory,string userName, JwtIssuerOptions jwtOptions, JsonSerializerSettings serializerSettings)
{
var response = new
{
id = identity.Claims.Single(c => c.Type == "id").Value,
auth_token = await jwtFactory.GenerateEncodedToken(userName, identity),
expires_in = (int)jwtOptions.ValidFor.TotalSeconds
}; // see GenerateEncodedToken pasted below.

return JsonConvert.SerializeObject(response, serializerSettings);
}

public async Task<string> GenerateEncodedToken(string userName, ClaimsIdentity identity)
{
var claims = new
{
new Claim(JwtRegisteredClaimNames.Sub, userName),
new Claim(JwtRegisteredClaimNames.Jti, await _jwtOptions.JtiGenerator()),
new Claim(JwtRegisteredClaimNames.Iat, ToUnixEpochDate(_jwtOptions.IssuedAt).ToString(), ClaimValueTypes.Integer64),
identity.FindFirst(Helpers.Constants.Strings.JwtClaimIdentifiers.Rol),
identity.FindFirst(Helpers.Constants.Strings.JwtClaimIdentifiers.Id)
};

// Create the JWT security token and encode it.
var jwt = new JwtSecurityToken(
issuer: _jwtOptions.Issuer,
audience: _jwtOptions.Audience,
claims: claims,
notBefore: _jwtOptions.NotBefore,
expires: _jwtOptions.Expiration,
signingCredentials: _jwtOptions.SigningCredentials);

var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);

return encodedJwt;
}


These are the relevant lines in ConfigureServices.



  // jwt wire up
// Get options from app settings
var jwtAppSettingOptions = Configuration.GetSection(nameof(JwtIssuerOptions));

// Configure JwtIssuerOptions
services.Configure<JwtIssuerOptions>(options =>
{
options.Issuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)];
options.Audience = jwtAppSettingOptions[nameof(JwtIssuerOptions.Audience)];
options.SigningCredentials = new SigningCredentials(_signingKey, SecurityAlgorithms.HmacSha256);
});

var tokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)],

ValidateAudience = true,
ValidAudience = jwtAppSettingOptions[nameof(JwtIssuerOptions.Audience)],

ValidateIssuerSigningKey = true,
IssuerSigningKey = _signingKey,

RequireExpirationTime = false,
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero
};

services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;

}).AddJwtBearer(configureOptions =>
{
configureOptions.ClaimsIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)];
configureOptions.TokenValidationParameters = tokenValidationParameters;
configureOptions.SaveToken = true;
configureOptions.RequireHttpsMetadata = false;
});

// api user claim policy
services.AddAuthorization(options =>
{
options.AddPolicy("ApiUser", policy => policy.RequireClaim(Constants.Strings.JwtClaimIdentifiers.Rol, Constants.Strings.JwtClaims.ApiAccess));
});

// add identity
var builder = services.AddIdentity<AppUser, AppRole>(o =>
{
// configure identity options
o.Password.RequireDigit = false;
o.Password.RequireLowercase = false;
o.Password.RequireUppercase = false;
o.Password.RequireNonAlphanumeric = false;
o.Password.RequiredLength = 6;
})
.AddSignInManager<SignInManager<AppUser>>()
.AddEntityFrameworkStores<AppIdentityDbContext>()
.AddDefaultTokenProviders();


I'm using the following to pass my token from Angular.



  private authHeader(): HttpHeaders {
let headers = new HttpHeaders();
if (isPlatformBrowser(this.platformId)) {
headers = headers.set('Content-Type', 'application/json');
let authToken = this.windowRefService.nativeWindow.localStorage.getItem('auth_token');
headers = headers.set('Authorization', authToken);
headers = headers.set('X-XSRF-TOKEN', this.getCookie('XSRF-TOKEN'));
}

return headers;
}

protected jsonAuthRequestOptions = { headers: this.authHeader() };

public loggedInAs(): Observable<string> {
return this.http.post<any>(this.baseUrl + "api/Account/GetUserId", { } , this.jsonAuthRequestOptions)
.map(data => {
if (data) {
return data;
}

return '';
})
.catch(this.handleError);
}


Does JWT authentication automatically set HttpContext.User? Or do I have to do that explicitly?



My succeeding call fails. (User has no claims, though HttpContext.User is not null.) I don't know whether the problem is with relying on HttpContext.User, or whether there is something wrong with the token generation / consumption.










share|improve this question
























  • Are you calling services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(... and app.UseAuthentication(); in Startup.cs?
    – Albert
    yesterday












  • Yes. services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }).AddJwtBearer(configureOptions => { configureOptions.ClaimsIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)]; configureOptions.TokenValidationParameters = tokenValidationParameters; configureOptions.SaveToken = true; });
    – Jonas Arcangel
    yesterday










  • And did you set the app.UseAuthentication() on Configure method within Startup.cs file as well, before the UseMvc? Double-check here
    – Anderson Matos
    yesterday










  • I also have app.UseAuthentication() as well as app.UseJwtTokenMiddleware() before UseMvc().
    – Jonas Arcangel
    yesterday










  • HttpContext.User exists, so I think it is getting authenticated. It's just that the Claims is empty.
    – Jonas Arcangel
    yesterday















up vote
0
down vote

favorite
1












I have the following for my login code, and another method to retrieve the user ID in another call.



        // POST: /api/Account/Login
[HttpPost]
[AllowAnonymous]
public async Task<IActionResult> Login([FromBody]LoginViewModel model)
{
if (ModelState.IsValid)
{
var user = await _userManager.FindByEmailAsync(model.Email);
if (user != null)
{
if (!await _userManager.IsEmailConfirmedAsync(user))
{
ModelState.AddModelError(string.Empty,
"You must have a confirmed email to log in.");
return BadRequest(Errors.AddErrorToModelState("Email", "You must have a confirmed email to log in.", ModelState));
}
}

var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false);

if (result.Succeeded)
{
// IS THIS NEEDED? --> // HttpContext.User = await _userClaimsPrincipalFactory.CreateAsync(user);
var tokens = _antiforgery.GetAndStoreTokens(HttpContext);

var identity = _jwtFactory.GenerateClaimsIdentity(model.Email, user.Id);
_logger.LogInformation(1, "User logged in.");
var jwt = await Tokens.GenerateJwt(identity, _jwtFactory, model.Email, _jwtOptions, new JsonSerializerSettings { Formatting = Formatting.Indented });
return new OkObjectResult(jwt);
}

if (result.RequiresTwoFactor)
{
//return RedirectToAction(nameof(SendCode), new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
}

if (result.IsLockedOut)
{
string message = "User account locked out.";
_logger.LogWarning(2, message);
return BadRequest(Errors.AddErrorToModelState("Email", message, ModelState));
}

if (result.IsNotAllowed)
{
string message = "User account is not allowed to sign in.";
_logger.LogWarning(2, message);
return BadRequest(Errors.AddErrorToModelState("Email", message, ModelState));
}

return BadRequest(Errors.AddErrorToModelState("", "Sign in failed.", ModelState));
}

return BadRequest(Errors.AddErrorToModelState("", "", ModelState));
}

public string GetUserId()
{
string username = string.Empty;

ClaimsPrincipal principal = HttpContext.User as ClaimsPrincipal;

if (HttpContext.User != null)
{
var id = HttpContext.User.FindFirst(ClaimTypes.NameIdentifier);

if (id != null)
{
username = id.Value;
}
}

return username;
}


This is the code for GenerateJwt. (Are these fields standard? I see other fields being set in other code, such as in https://code-maze.com/authentication-aspnetcore-jwt-1/.)



  public static async Task<string> GenerateJwt(ClaimsIdentity identity, IJwtFactory jwtFactory,string userName, JwtIssuerOptions jwtOptions, JsonSerializerSettings serializerSettings)
{
var response = new
{
id = identity.Claims.Single(c => c.Type == "id").Value,
auth_token = await jwtFactory.GenerateEncodedToken(userName, identity),
expires_in = (int)jwtOptions.ValidFor.TotalSeconds
}; // see GenerateEncodedToken pasted below.

return JsonConvert.SerializeObject(response, serializerSettings);
}

public async Task<string> GenerateEncodedToken(string userName, ClaimsIdentity identity)
{
var claims = new
{
new Claim(JwtRegisteredClaimNames.Sub, userName),
new Claim(JwtRegisteredClaimNames.Jti, await _jwtOptions.JtiGenerator()),
new Claim(JwtRegisteredClaimNames.Iat, ToUnixEpochDate(_jwtOptions.IssuedAt).ToString(), ClaimValueTypes.Integer64),
identity.FindFirst(Helpers.Constants.Strings.JwtClaimIdentifiers.Rol),
identity.FindFirst(Helpers.Constants.Strings.JwtClaimIdentifiers.Id)
};

// Create the JWT security token and encode it.
var jwt = new JwtSecurityToken(
issuer: _jwtOptions.Issuer,
audience: _jwtOptions.Audience,
claims: claims,
notBefore: _jwtOptions.NotBefore,
expires: _jwtOptions.Expiration,
signingCredentials: _jwtOptions.SigningCredentials);

var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);

return encodedJwt;
}


These are the relevant lines in ConfigureServices.



  // jwt wire up
// Get options from app settings
var jwtAppSettingOptions = Configuration.GetSection(nameof(JwtIssuerOptions));

// Configure JwtIssuerOptions
services.Configure<JwtIssuerOptions>(options =>
{
options.Issuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)];
options.Audience = jwtAppSettingOptions[nameof(JwtIssuerOptions.Audience)];
options.SigningCredentials = new SigningCredentials(_signingKey, SecurityAlgorithms.HmacSha256);
});

var tokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)],

ValidateAudience = true,
ValidAudience = jwtAppSettingOptions[nameof(JwtIssuerOptions.Audience)],

ValidateIssuerSigningKey = true,
IssuerSigningKey = _signingKey,

RequireExpirationTime = false,
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero
};

services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;

}).AddJwtBearer(configureOptions =>
{
configureOptions.ClaimsIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)];
configureOptions.TokenValidationParameters = tokenValidationParameters;
configureOptions.SaveToken = true;
configureOptions.RequireHttpsMetadata = false;
});

// api user claim policy
services.AddAuthorization(options =>
{
options.AddPolicy("ApiUser", policy => policy.RequireClaim(Constants.Strings.JwtClaimIdentifiers.Rol, Constants.Strings.JwtClaims.ApiAccess));
});

// add identity
var builder = services.AddIdentity<AppUser, AppRole>(o =>
{
// configure identity options
o.Password.RequireDigit = false;
o.Password.RequireLowercase = false;
o.Password.RequireUppercase = false;
o.Password.RequireNonAlphanumeric = false;
o.Password.RequiredLength = 6;
})
.AddSignInManager<SignInManager<AppUser>>()
.AddEntityFrameworkStores<AppIdentityDbContext>()
.AddDefaultTokenProviders();


I'm using the following to pass my token from Angular.



  private authHeader(): HttpHeaders {
let headers = new HttpHeaders();
if (isPlatformBrowser(this.platformId)) {
headers = headers.set('Content-Type', 'application/json');
let authToken = this.windowRefService.nativeWindow.localStorage.getItem('auth_token');
headers = headers.set('Authorization', authToken);
headers = headers.set('X-XSRF-TOKEN', this.getCookie('XSRF-TOKEN'));
}

return headers;
}

protected jsonAuthRequestOptions = { headers: this.authHeader() };

public loggedInAs(): Observable<string> {
return this.http.post<any>(this.baseUrl + "api/Account/GetUserId", { } , this.jsonAuthRequestOptions)
.map(data => {
if (data) {
return data;
}

return '';
})
.catch(this.handleError);
}


Does JWT authentication automatically set HttpContext.User? Or do I have to do that explicitly?



My succeeding call fails. (User has no claims, though HttpContext.User is not null.) I don't know whether the problem is with relying on HttpContext.User, or whether there is something wrong with the token generation / consumption.










share|improve this question
























  • Are you calling services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(... and app.UseAuthentication(); in Startup.cs?
    – Albert
    yesterday












  • Yes. services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }).AddJwtBearer(configureOptions => { configureOptions.ClaimsIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)]; configureOptions.TokenValidationParameters = tokenValidationParameters; configureOptions.SaveToken = true; });
    – Jonas Arcangel
    yesterday










  • And did you set the app.UseAuthentication() on Configure method within Startup.cs file as well, before the UseMvc? Double-check here
    – Anderson Matos
    yesterday










  • I also have app.UseAuthentication() as well as app.UseJwtTokenMiddleware() before UseMvc().
    – Jonas Arcangel
    yesterday










  • HttpContext.User exists, so I think it is getting authenticated. It's just that the Claims is empty.
    – Jonas Arcangel
    yesterday













up vote
0
down vote

favorite
1









up vote
0
down vote

favorite
1






1





I have the following for my login code, and another method to retrieve the user ID in another call.



        // POST: /api/Account/Login
[HttpPost]
[AllowAnonymous]
public async Task<IActionResult> Login([FromBody]LoginViewModel model)
{
if (ModelState.IsValid)
{
var user = await _userManager.FindByEmailAsync(model.Email);
if (user != null)
{
if (!await _userManager.IsEmailConfirmedAsync(user))
{
ModelState.AddModelError(string.Empty,
"You must have a confirmed email to log in.");
return BadRequest(Errors.AddErrorToModelState("Email", "You must have a confirmed email to log in.", ModelState));
}
}

var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false);

if (result.Succeeded)
{
// IS THIS NEEDED? --> // HttpContext.User = await _userClaimsPrincipalFactory.CreateAsync(user);
var tokens = _antiforgery.GetAndStoreTokens(HttpContext);

var identity = _jwtFactory.GenerateClaimsIdentity(model.Email, user.Id);
_logger.LogInformation(1, "User logged in.");
var jwt = await Tokens.GenerateJwt(identity, _jwtFactory, model.Email, _jwtOptions, new JsonSerializerSettings { Formatting = Formatting.Indented });
return new OkObjectResult(jwt);
}

if (result.RequiresTwoFactor)
{
//return RedirectToAction(nameof(SendCode), new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
}

if (result.IsLockedOut)
{
string message = "User account locked out.";
_logger.LogWarning(2, message);
return BadRequest(Errors.AddErrorToModelState("Email", message, ModelState));
}

if (result.IsNotAllowed)
{
string message = "User account is not allowed to sign in.";
_logger.LogWarning(2, message);
return BadRequest(Errors.AddErrorToModelState("Email", message, ModelState));
}

return BadRequest(Errors.AddErrorToModelState("", "Sign in failed.", ModelState));
}

return BadRequest(Errors.AddErrorToModelState("", "", ModelState));
}

public string GetUserId()
{
string username = string.Empty;

ClaimsPrincipal principal = HttpContext.User as ClaimsPrincipal;

if (HttpContext.User != null)
{
var id = HttpContext.User.FindFirst(ClaimTypes.NameIdentifier);

if (id != null)
{
username = id.Value;
}
}

return username;
}


This is the code for GenerateJwt. (Are these fields standard? I see other fields being set in other code, such as in https://code-maze.com/authentication-aspnetcore-jwt-1/.)



  public static async Task<string> GenerateJwt(ClaimsIdentity identity, IJwtFactory jwtFactory,string userName, JwtIssuerOptions jwtOptions, JsonSerializerSettings serializerSettings)
{
var response = new
{
id = identity.Claims.Single(c => c.Type == "id").Value,
auth_token = await jwtFactory.GenerateEncodedToken(userName, identity),
expires_in = (int)jwtOptions.ValidFor.TotalSeconds
}; // see GenerateEncodedToken pasted below.

return JsonConvert.SerializeObject(response, serializerSettings);
}

public async Task<string> GenerateEncodedToken(string userName, ClaimsIdentity identity)
{
var claims = new
{
new Claim(JwtRegisteredClaimNames.Sub, userName),
new Claim(JwtRegisteredClaimNames.Jti, await _jwtOptions.JtiGenerator()),
new Claim(JwtRegisteredClaimNames.Iat, ToUnixEpochDate(_jwtOptions.IssuedAt).ToString(), ClaimValueTypes.Integer64),
identity.FindFirst(Helpers.Constants.Strings.JwtClaimIdentifiers.Rol),
identity.FindFirst(Helpers.Constants.Strings.JwtClaimIdentifiers.Id)
};

// Create the JWT security token and encode it.
var jwt = new JwtSecurityToken(
issuer: _jwtOptions.Issuer,
audience: _jwtOptions.Audience,
claims: claims,
notBefore: _jwtOptions.NotBefore,
expires: _jwtOptions.Expiration,
signingCredentials: _jwtOptions.SigningCredentials);

var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);

return encodedJwt;
}


These are the relevant lines in ConfigureServices.



  // jwt wire up
// Get options from app settings
var jwtAppSettingOptions = Configuration.GetSection(nameof(JwtIssuerOptions));

// Configure JwtIssuerOptions
services.Configure<JwtIssuerOptions>(options =>
{
options.Issuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)];
options.Audience = jwtAppSettingOptions[nameof(JwtIssuerOptions.Audience)];
options.SigningCredentials = new SigningCredentials(_signingKey, SecurityAlgorithms.HmacSha256);
});

var tokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)],

ValidateAudience = true,
ValidAudience = jwtAppSettingOptions[nameof(JwtIssuerOptions.Audience)],

ValidateIssuerSigningKey = true,
IssuerSigningKey = _signingKey,

RequireExpirationTime = false,
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero
};

services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;

}).AddJwtBearer(configureOptions =>
{
configureOptions.ClaimsIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)];
configureOptions.TokenValidationParameters = tokenValidationParameters;
configureOptions.SaveToken = true;
configureOptions.RequireHttpsMetadata = false;
});

// api user claim policy
services.AddAuthorization(options =>
{
options.AddPolicy("ApiUser", policy => policy.RequireClaim(Constants.Strings.JwtClaimIdentifiers.Rol, Constants.Strings.JwtClaims.ApiAccess));
});

// add identity
var builder = services.AddIdentity<AppUser, AppRole>(o =>
{
// configure identity options
o.Password.RequireDigit = false;
o.Password.RequireLowercase = false;
o.Password.RequireUppercase = false;
o.Password.RequireNonAlphanumeric = false;
o.Password.RequiredLength = 6;
})
.AddSignInManager<SignInManager<AppUser>>()
.AddEntityFrameworkStores<AppIdentityDbContext>()
.AddDefaultTokenProviders();


I'm using the following to pass my token from Angular.



  private authHeader(): HttpHeaders {
let headers = new HttpHeaders();
if (isPlatformBrowser(this.platformId)) {
headers = headers.set('Content-Type', 'application/json');
let authToken = this.windowRefService.nativeWindow.localStorage.getItem('auth_token');
headers = headers.set('Authorization', authToken);
headers = headers.set('X-XSRF-TOKEN', this.getCookie('XSRF-TOKEN'));
}

return headers;
}

protected jsonAuthRequestOptions = { headers: this.authHeader() };

public loggedInAs(): Observable<string> {
return this.http.post<any>(this.baseUrl + "api/Account/GetUserId", { } , this.jsonAuthRequestOptions)
.map(data => {
if (data) {
return data;
}

return '';
})
.catch(this.handleError);
}


Does JWT authentication automatically set HttpContext.User? Or do I have to do that explicitly?



My succeeding call fails. (User has no claims, though HttpContext.User is not null.) I don't know whether the problem is with relying on HttpContext.User, or whether there is something wrong with the token generation / consumption.










share|improve this question















I have the following for my login code, and another method to retrieve the user ID in another call.



        // POST: /api/Account/Login
[HttpPost]
[AllowAnonymous]
public async Task<IActionResult> Login([FromBody]LoginViewModel model)
{
if (ModelState.IsValid)
{
var user = await _userManager.FindByEmailAsync(model.Email);
if (user != null)
{
if (!await _userManager.IsEmailConfirmedAsync(user))
{
ModelState.AddModelError(string.Empty,
"You must have a confirmed email to log in.");
return BadRequest(Errors.AddErrorToModelState("Email", "You must have a confirmed email to log in.", ModelState));
}
}

var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false);

if (result.Succeeded)
{
// IS THIS NEEDED? --> // HttpContext.User = await _userClaimsPrincipalFactory.CreateAsync(user);
var tokens = _antiforgery.GetAndStoreTokens(HttpContext);

var identity = _jwtFactory.GenerateClaimsIdentity(model.Email, user.Id);
_logger.LogInformation(1, "User logged in.");
var jwt = await Tokens.GenerateJwt(identity, _jwtFactory, model.Email, _jwtOptions, new JsonSerializerSettings { Formatting = Formatting.Indented });
return new OkObjectResult(jwt);
}

if (result.RequiresTwoFactor)
{
//return RedirectToAction(nameof(SendCode), new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
}

if (result.IsLockedOut)
{
string message = "User account locked out.";
_logger.LogWarning(2, message);
return BadRequest(Errors.AddErrorToModelState("Email", message, ModelState));
}

if (result.IsNotAllowed)
{
string message = "User account is not allowed to sign in.";
_logger.LogWarning(2, message);
return BadRequest(Errors.AddErrorToModelState("Email", message, ModelState));
}

return BadRequest(Errors.AddErrorToModelState("", "Sign in failed.", ModelState));
}

return BadRequest(Errors.AddErrorToModelState("", "", ModelState));
}

public string GetUserId()
{
string username = string.Empty;

ClaimsPrincipal principal = HttpContext.User as ClaimsPrincipal;

if (HttpContext.User != null)
{
var id = HttpContext.User.FindFirst(ClaimTypes.NameIdentifier);

if (id != null)
{
username = id.Value;
}
}

return username;
}


This is the code for GenerateJwt. (Are these fields standard? I see other fields being set in other code, such as in https://code-maze.com/authentication-aspnetcore-jwt-1/.)



  public static async Task<string> GenerateJwt(ClaimsIdentity identity, IJwtFactory jwtFactory,string userName, JwtIssuerOptions jwtOptions, JsonSerializerSettings serializerSettings)
{
var response = new
{
id = identity.Claims.Single(c => c.Type == "id").Value,
auth_token = await jwtFactory.GenerateEncodedToken(userName, identity),
expires_in = (int)jwtOptions.ValidFor.TotalSeconds
}; // see GenerateEncodedToken pasted below.

return JsonConvert.SerializeObject(response, serializerSettings);
}

public async Task<string> GenerateEncodedToken(string userName, ClaimsIdentity identity)
{
var claims = new
{
new Claim(JwtRegisteredClaimNames.Sub, userName),
new Claim(JwtRegisteredClaimNames.Jti, await _jwtOptions.JtiGenerator()),
new Claim(JwtRegisteredClaimNames.Iat, ToUnixEpochDate(_jwtOptions.IssuedAt).ToString(), ClaimValueTypes.Integer64),
identity.FindFirst(Helpers.Constants.Strings.JwtClaimIdentifiers.Rol),
identity.FindFirst(Helpers.Constants.Strings.JwtClaimIdentifiers.Id)
};

// Create the JWT security token and encode it.
var jwt = new JwtSecurityToken(
issuer: _jwtOptions.Issuer,
audience: _jwtOptions.Audience,
claims: claims,
notBefore: _jwtOptions.NotBefore,
expires: _jwtOptions.Expiration,
signingCredentials: _jwtOptions.SigningCredentials);

var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);

return encodedJwt;
}


These are the relevant lines in ConfigureServices.



  // jwt wire up
// Get options from app settings
var jwtAppSettingOptions = Configuration.GetSection(nameof(JwtIssuerOptions));

// Configure JwtIssuerOptions
services.Configure<JwtIssuerOptions>(options =>
{
options.Issuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)];
options.Audience = jwtAppSettingOptions[nameof(JwtIssuerOptions.Audience)];
options.SigningCredentials = new SigningCredentials(_signingKey, SecurityAlgorithms.HmacSha256);
});

var tokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)],

ValidateAudience = true,
ValidAudience = jwtAppSettingOptions[nameof(JwtIssuerOptions.Audience)],

ValidateIssuerSigningKey = true,
IssuerSigningKey = _signingKey,

RequireExpirationTime = false,
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero
};

services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;

}).AddJwtBearer(configureOptions =>
{
configureOptions.ClaimsIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)];
configureOptions.TokenValidationParameters = tokenValidationParameters;
configureOptions.SaveToken = true;
configureOptions.RequireHttpsMetadata = false;
});

// api user claim policy
services.AddAuthorization(options =>
{
options.AddPolicy("ApiUser", policy => policy.RequireClaim(Constants.Strings.JwtClaimIdentifiers.Rol, Constants.Strings.JwtClaims.ApiAccess));
});

// add identity
var builder = services.AddIdentity<AppUser, AppRole>(o =>
{
// configure identity options
o.Password.RequireDigit = false;
o.Password.RequireLowercase = false;
o.Password.RequireUppercase = false;
o.Password.RequireNonAlphanumeric = false;
o.Password.RequiredLength = 6;
})
.AddSignInManager<SignInManager<AppUser>>()
.AddEntityFrameworkStores<AppIdentityDbContext>()
.AddDefaultTokenProviders();


I'm using the following to pass my token from Angular.



  private authHeader(): HttpHeaders {
let headers = new HttpHeaders();
if (isPlatformBrowser(this.platformId)) {
headers = headers.set('Content-Type', 'application/json');
let authToken = this.windowRefService.nativeWindow.localStorage.getItem('auth_token');
headers = headers.set('Authorization', authToken);
headers = headers.set('X-XSRF-TOKEN', this.getCookie('XSRF-TOKEN'));
}

return headers;
}

protected jsonAuthRequestOptions = { headers: this.authHeader() };

public loggedInAs(): Observable<string> {
return this.http.post<any>(this.baseUrl + "api/Account/GetUserId", { } , this.jsonAuthRequestOptions)
.map(data => {
if (data) {
return data;
}

return '';
})
.catch(this.handleError);
}


Does JWT authentication automatically set HttpContext.User? Or do I have to do that explicitly?



My succeeding call fails. (User has no claims, though HttpContext.User is not null.) I don't know whether the problem is with relying on HttpContext.User, or whether there is something wrong with the token generation / consumption.







asp.net-core jwt






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 6 hours ago

























asked yesterday









Jonas Arcangel

1,82443162




1,82443162












  • Are you calling services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(... and app.UseAuthentication(); in Startup.cs?
    – Albert
    yesterday












  • Yes. services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }).AddJwtBearer(configureOptions => { configureOptions.ClaimsIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)]; configureOptions.TokenValidationParameters = tokenValidationParameters; configureOptions.SaveToken = true; });
    – Jonas Arcangel
    yesterday










  • And did you set the app.UseAuthentication() on Configure method within Startup.cs file as well, before the UseMvc? Double-check here
    – Anderson Matos
    yesterday










  • I also have app.UseAuthentication() as well as app.UseJwtTokenMiddleware() before UseMvc().
    – Jonas Arcangel
    yesterday










  • HttpContext.User exists, so I think it is getting authenticated. It's just that the Claims is empty.
    – Jonas Arcangel
    yesterday


















  • Are you calling services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(... and app.UseAuthentication(); in Startup.cs?
    – Albert
    yesterday












  • Yes. services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }).AddJwtBearer(configureOptions => { configureOptions.ClaimsIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)]; configureOptions.TokenValidationParameters = tokenValidationParameters; configureOptions.SaveToken = true; });
    – Jonas Arcangel
    yesterday










  • And did you set the app.UseAuthentication() on Configure method within Startup.cs file as well, before the UseMvc? Double-check here
    – Anderson Matos
    yesterday










  • I also have app.UseAuthentication() as well as app.UseJwtTokenMiddleware() before UseMvc().
    – Jonas Arcangel
    yesterday










  • HttpContext.User exists, so I think it is getting authenticated. It's just that the Claims is empty.
    – Jonas Arcangel
    yesterday
















Are you calling services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(... and app.UseAuthentication(); in Startup.cs?
– Albert
yesterday






Are you calling services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(... and app.UseAuthentication(); in Startup.cs?
– Albert
yesterday














Yes. services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }).AddJwtBearer(configureOptions => { configureOptions.ClaimsIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)]; configureOptions.TokenValidationParameters = tokenValidationParameters; configureOptions.SaveToken = true; });
– Jonas Arcangel
yesterday




Yes. services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }).AddJwtBearer(configureOptions => { configureOptions.ClaimsIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)]; configureOptions.TokenValidationParameters = tokenValidationParameters; configureOptions.SaveToken = true; });
– Jonas Arcangel
yesterday












And did you set the app.UseAuthentication() on Configure method within Startup.cs file as well, before the UseMvc? Double-check here
– Anderson Matos
yesterday




And did you set the app.UseAuthentication() on Configure method within Startup.cs file as well, before the UseMvc? Double-check here
– Anderson Matos
yesterday












I also have app.UseAuthentication() as well as app.UseJwtTokenMiddleware() before UseMvc().
– Jonas Arcangel
yesterday




I also have app.UseAuthentication() as well as app.UseJwtTokenMiddleware() before UseMvc().
– Jonas Arcangel
yesterday












HttpContext.User exists, so I think it is getting authenticated. It's just that the Claims is empty.
– Jonas Arcangel
yesterday




HttpContext.User exists, so I think it is getting authenticated. It's just that the Claims is empty.
– Jonas Arcangel
yesterday

















active

oldest

votes











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














 

draft saved


draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53237854%2fasp-net-core-jwt-login-not-setting-httpcontext-user-claims%23new-answer', 'question_page');
}
);

Post as a guest





































active

oldest

votes













active

oldest

votes









active

oldest

votes






active

oldest

votes
















 

draft saved


draft discarded



















































 


draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53237854%2fasp-net-core-jwt-login-not-setting-httpcontext-user-claims%23new-answer', 'question_page');
}
);

Post as a guest




















































































Popular posts from this blog

Full-time equivalent

Bicuculline

さくらももこ