The Project consists of two Parts:
- ASP.Net Core API
- ASP.Net Core MVC Frontend
Basically, what I want to do is authentication via JWT. So the API issues JWT and the MVC Frontend uses Identity with the claims and roles declared in the JWT.
Startup.cs in the API:
private const string SecretKey = "my_Secret_Key";
private readonly SymmetricSecurityKey _signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(SecretKey));
#region JWT Auth
// 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;
});
// api user claim policy
services.AddAuthorization(options =>
{
options.AddPolicy(Constants.Policies.ApiAccess, policy => policy.RequireClaim(Constants.JwtClaimIdentifiers.Rol, Constants.JwtClaims.ApiAccess));
});
#endregion
JWT Generation:
public async Task<string> GenerateEncodedToken(string userName)
{
User user = _userManager.GetUserByUserName(userName);
List<string> userRoles = _userManager.GetRoles(user.Guid);
var claimsToEncode = new[]
{
new Claim(JwtRegisteredClaimNames.Sub, userName),
new Claim("web", user.WebId),
new Claim(JwtRegisteredClaimNames.Jti, await _jwtOptions.JtiGenerator()),
new Claim(JwtRegisteredClaimNames.Iat, ToUnixEpochDate(_jwtOptions.IssuedAt).ToString(), ClaimValueTypes.Integer64),
new Claim(Constants.JwtClaimIdentifiers.Rol,Constants.JwtClaims.ApiAccess),
};
// Create the JWT security token and encode it.
var jwt = new JwtSecurityToken(
issuer: _jwtOptions.Issuer,
audience: _jwtOptions.Audience,
claims: claimsToEncode,
notBefore: _jwtOptions.NotBefore,
expires: _jwtOptions.Expiration,
signingCredentials: _jwtOptions.SigningCredentials);
jwt.Payload.Add("roles", userRoles.ToArray());
var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);
return encodedJwt;
}
Authorization works like a charm with this in the API.
Now I want to do the following: Implement the same in the Frontend, so that: MVC Frontend receives Credentials, send them to the API, get Token, and Authorize with the Claims and Roles in the Token.
I tried several things, but none of them worked so far. What do I have to insert in the Startup.cs in the Frontend so that Identity checks not against the secret key (which the Frontend is not allowed to have) but against a public key? Or do I have to implement a Endpoint in the API which validates the JWT remotely?