ASP.NET Core Delete Cookies after JWT expire - asp.net

I store my JWT in HTTPOnly Cookies, and after the token expire, the cookie still active. How can I delete or expire the cookie, when the JTW expires too?
Here is my Startup:
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"])),
ClockSkew = TimeSpan.Zero
};
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;
});
At Login, I pass my JWT to the cookie:
Response.Cookies.Append("X-Access-Token", generatedToken, new CookieOptions() { HttpOnly = true, SameSite = SameSiteMode.Strict, Secure = true });

Related

SignalR Authentication Identity is always null

I have a WPF app that I am connecting to a SignalR API. However, I am having some issues with my Identity. When I actually call an API Endpoint GET, POST, PUT, or DELETE The Identity is populated correctly (all of the claims are there). When I am connecting to SignalR the Identity Claims are not there.
This is where I register my Jwt token
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:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["Jwt:Key"]))
};
options.Authority = configuration["Jwt:Authority"];
options.RequireHttpsMetadata = false;
options.SaveToken = true;
options.Events = new JwtBearerEvents()
{
OnMessageReceived = context =>
{
var accessToken = context.Request.Query["access_token"];
// If the request is for our hub...
var path = context.HttpContext.Request.Path;
if (!string.IsNullOrEmpty(accessToken) &&
(path.StartsWithSegments("/hubs")))
{
// Read the token out of the query string
context.Token = accessToken;
}
return Task.CompletedTask;
},
};
});
and here is where I register my connection
_connection = new HubConnectionBuilder()
.ConfigureLogging(logBuilder =>
{
logBuilder.AddConsole();
logBuilder.AddDebug();
})
.WithUrl($"{url}/hubs", options =>
{
options.AccessTokenProvider = _userService.GetToken;//returns Task.FromResult(userToken)
})
.WithAutomaticReconnect(new[]
{
TimeSpan.Zero,
TimeSpan.FromSeconds(2),
TimeSpan.FromSeconds(10),
TimeSpan.FromSeconds(30),
TimeSpan.FromSeconds(60),
TimeSpan.FromSeconds(120)
})
.Build();
My Jwt object in configuration
"jwt":{
"Key":"some random generated key",
"Issuer":"https://localhost:5001/",
"Audience":"https://localhost:5001/",
"Authority":"https://localhost:5001/"
},
Can you please explain what I am doing wrong here?
I actually found the answer to my own question.
I changed
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
to
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
});
and that did it!
Hope this helps someone else.

Scheme already exists: Bearer

I'm implementing login using Microsoft provider also implement the default login using jwt
when I run the project I got this error (Scheme already exists: Bearer)
when i comment this part, project run successfully
//.AddJwtBearer(x =>
// {
// x.SaveToken = true;
// x.TokenValidationParameters = tokenValidationParameters;
// })
here is my code
var jwtSettings = new JWTSettings();
var tokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(jwtSettings.Secret)),
ValidateIssuer = false,
ValidateAudience = false,
RequireExpirationTime = false,
ValidateLifetime = true
};
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(x =>
{
x.SaveToken = true;
x.TokenValidationParameters = tokenValidationParameters;
})
.AddMicrosoftIdentityWebApi(configuration, "AzureAd")
.EnableTokenAcquisitionToCallDownstreamApi()
.AddMicrosoftGraph(configuration.GetSection("DownstreamApi"))
.AddInMemoryTokenCaches();
Scheme already exists: Bearer
It means you have more than one schemes with the same name.
You can try to set the parameter authenticationScheme into JwtBearerExtensions.AddJwtBearer Method.Here is the official doc.
And if you want to select the scheme,you can refer to the doc,and try to use:
[Authorize(AuthenticationSchemes = xxx)]

Dotnet JWT Bearer TokenValidationParameters issue - Unauthorized? Role(Policy) based authorization doesnt work

I changed the setting in the TokenValidationParameters (ValidateIssuer,ValidateAudience) from False to True.
What the settings used to be (startup) - everything was working perfectly.
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(config["TokenKey"])),
ValidateIssuer = false,
ValidateAudience = false,
};
});
Now every call to the API the requires to authorized stopped working.
The new settings - stopped working
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(config["TokenKey"])),
ValidateIssuer = true,
ValidateAudience = true,
};
});
Every call to the API that needs to be authorized now is getting unauthorized.
This is my token service:
public class TokenService : ITokenService
{
private readonly SymmetricSecurityKey _key;
private readonly UserManager<AppUser> _userManager;
public TokenService(IConfiguration config, UserManager<AppUser> userManager)
{
this._userManager = userManager;
_key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(config["TokenKey"]));
}
public async Task<string> CreateToken(AppUser user)
{
var claims = new List<Claim>
{
new Claim(JwtRegisteredClaimNames.NameId, user.Id.ToString()),
new Claim(JwtRegisteredClaimNames.UniqueName, user.UserName)
};
var roles = await _userManager.GetRolesAsync(user);
claims.AddRange(roles.Select(role => new Claim(ClaimTypes.Role, role)));
var creds = new SigningCredentials(_key, SecurityAlgorithms.HmacSha512Signature);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(claims),
Expires = DateTime.Now.AddDays(7),
SigningCredentials = creds
};
var tokenHandler = new JwtSecurityTokenHandler();
var token = tokenHandler.CreateToken(tokenDescriptor);
return tokenHandler.WriteToken(token);
}
}
Does anyone can please explain to me what causes it so I could learn. And how can I fix it ? I tried many ways but unfortunately, nothing seems to work for me.
Thank you so much.
This is the code at GitHub just in case : https://github.com/davidax0204/HeroMain.git
When you set ValidateIssuer and ValidateAudience to true, you should set value for ValidIssuer and ValidAudience when creating JWT and SecurityTokenDescriptor
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(claims),
Expires = DateTime.Now.AddDays(7),
SigningCredentials = creds,
Audience = "YourAudience",
Issuer = "YourIssuer"
};
And adding same value to TokenValidationParameters properties
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(config["TokenKey"])),
ValidateIssuer = true,
ValidIssuer = "YourIssuer",
ValidateAudience = true,
ValidAudience = "YourAudience"
};
});

SignalR core JWT authentication not working

I'm trying to authenticate with JWT in .NET Core 2.2 with SignalR. I don't get an error message that it doesn't work on either the server or the client-side. I have set breakpoints on the server-side where the authentication is supposed to happen. Does anyone have any idea why it's not working? The JWT is built with an asymmetric signature algorithm.
This is how I generate the JWT:
var utcNow = DateTime.UtcNow;
using (RSA privateRsa = RSA.Create())
{
privateRsa.FromXmlFile(Path.Combine(HttpContext.Current.Server.MapPath("~"),
"Keys",
ConfigurationManager.AppSettings["PrivateKey"]
));
var privateKey = new RsaSecurityKey(privateRsa);
SigningCredentials signingCredentials = new SigningCredentials(privateKey, SecurityAlgorithms.RsaSha256);
var claims = new Claim[]
{
new Claim(JwtRegisteredClaimNames.Sub, user.ID.ToString()),
//new Claim(JwtRegisteredClaimNames.NameId, user.FullName),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(JwtRegisteredClaimNames.Iat, utcNow.ToString())
};
var jwt = new JwtSecurityToken(
signingCredentials: signingCredentials,
claims: claims,
notBefore: utcNow,
expires: utcNow.AddMonths(12),
audience: "https://pacsonweb.com",
issuer: "PACSonWEB3 App"
);
return new JwtSecurityTokenHandler().WriteToken(jwt);
This is how i'm authenticating on the server side :
RsaSecurityKey signingKey = new RsaSecurityKey(publicRsa);
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(config =>
{
config.RequireHttpsMetadata = true;
config.SaveToken = true;
config.TokenValidationParameters = new TokenValidationParameters()
{
IssuerSigningKey = signingKey,
ValidateAudience = true,
ValidAudience = this.Configuration["Tokens:Audience"],
ValidateIssuer = true,
ValidIssuer = this.Configuration["Tokens:Issuer"],
ValidateLifetime = true,
ValidateIssuerSigningKey = true
};
});
This is how I send the JWT with SignalR on the client side:
hubConnection = new HubConnectionBuilder().WithUrl(hubUrl, (opts) =>
{
opts.AccessTokenProvider = () => Globals.GetJWTToken();
opts.HttpMessageHandlerFactory = (message) =>
{
if (message is HttpClientHandler clientHandler)
{
// bypass SSL certificate
clientHandler.ServerCertificateCustomValidationCallback += CheckCertificate;
clientHandler.CheckCertificateRevocationList = false;
}
return message;
};
}).Build();

JWT Token not expiring

I'm working on .net core api 2.1, I have implemented JWT token authentication, I want jwt token to expire after given time, but it is not expiring. Token still validation even after expiry time.
Startup.cs code:
// configure jwt authentication
var jwtSettings = jwtSettingsSection.Get<JWTSettings>();
var key = Encoding.ASCII.GetBytes(jwtSettings.SECRET);
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(x =>
{
x.RequireHttpsMetadata = false;
x.SaveToken = true;
x.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false,
ValidateAudience = false,
ValidateLifetime = false,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ClockSkew = TimeSpan.Zero
};
});
services.Configure<IISOptions>(options =>
{
options.AutomaticAuthentication = true;
//options.ForwardClientCertificate = true;
});
SignIn api code to create token on sign in:
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(_jwtSettings.SECRET);
var currentTime = DateTime.Now;
var tokenDescriptor = new SecurityTokenDescriptor
{
Expires = DateTime.Now.AddMinutes(2),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
};
var token = tokenHandler.CreateToken(tokenDescriptor);
var tokenString = tokenHandler.WriteToken(token);
rs.Token = tokenString;
Auth filter to validate token:
public void OnAuthorization(AuthorizationFilterContext filterContext)
{
if (!ValidateToken(filterContext.HttpContext.Request.Headers["TOKEN"]))
{
filterContext.Result = new UnauthorizedResult();
}
}
private bool ValidateToken(string authToken)
{
try
{
var tokenHandler = new JwtSecurityTokenHandler();
var validationParameters = GetValidationParameters();
SecurityToken validatedToken;
IPrincipal principal = tokenHandler.ValidateToken(authToken, validationParameters, out validatedToken);
return true;
}
catch(Exception ex)
{
return false;
}
}
private TokenValidationParameters GetValidationParameters()
{
return new TokenValidationParameters()
{
ValidateLifetime = false, // Because there is expiration in the generated token
ValidateAudience = false, // Because there is no audiance in the generated token
ValidateIssuer = false, // Because there is no issuer in the generated token
//ValidIssuer = _appSettings.ValidIssuer,
//ValidAudience = _appSettings.ValidAudience,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretkey)) // The same key as the one that generate the token
};
}
What can be the issue?

Resources