I am following this Tutorial and on Securing a controller with claim based authorization part I am getting a 404 Not Found error in Postman. I have exactly followed the tutorial, i am just running .net core v2.0.0 .
Tutorial's DashboardController.cs is in my project named as BordViewController.cs .
This is my BordViewController.cs . The problem is, control is not going in this class, but when i remove [Authorize(Policy = "ApiUser")] it works.
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace DotNetGigs
{
[Authorize(Policy = "ApiUser")]
[Route("api/[controller]")]
public class BordViewController : Controller
{
public BordViewController()
{
}
// GET api/dashboard/home
[HttpGet("home")]
public IActionResult GetHome()
{
return new OkObjectResult(new { Message = "This is secure data!" });
}
}
}
This is my startup.cs file
private readonly SymmetricSecurityKey _signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(SecretKey));
public Startup()
{
var builder = new ConfigurationBuilder();
builder.AddJsonFile(Path.Combine(Directory.GetCurrentDirectory().ToString(),"Configuration.json"));
Configuration = builder.Build();
}
public IConfiguration Configuration {get;set;}
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<AppDBcontext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),b=>b.MigrationsAssembly("LoginApp")));
services.AddSingleton<IJWTfactory, JWTFactory>();
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);});
services.AddAuthorization(options =>
{
options.AddPolicy("ApiUser", policy => policy.RequireClaim(Constants.Strings.JWTclaimIden.Rol, Constants.Strings.JWTclaims.ApiAccess));
});
services.AddIdentity<AppUser, IdentityRole>(o =>
{
// configure identity options
o.Password.RequireDigit = false;
o.Password.RequireLowercase = false;
o.Password.RequireUppercase = false;
o.Password.RequireNonAlphanumeric = false;
o.Password.RequiredLength = 6;
})
.AddEntityFrameworkStores<AppDBcontext>()
.AddDefaultTokenProviders();
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 = false,
ClockSkew = TimeSpan.Zero
};
services.AddAuthentication(options =>
{
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{ // options.Audience = Configuration.GetSection("TokenProviderOptions:Audience").Value;
//options.Issuer = Configuration.GetSection("TokenProviderOptions:Issuer").Value;
// options.SaveToken = true;
options.TokenValidationParameters = tokenValidationParameters;
options.RequireHttpsMetadata = false;
});
services.AddMvc().AddFluentValidation(fv => fv.RegisterValidatorsFromAssemblyContaining<Startup>());
services.AddAutoMapper();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseAuthentication();
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseMvc();
}
I am new to c# and .net core, if someone can help me figure out the mistake I am making I would be really grateful. Also please tell me if you want me to add some other files too.
Postman Code snippet
GET /api/boardview/home HTTP/1.1
Host: localhost:5000
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJuaWtoaWxrYTU4NUBnbWFpbC5jb20iLCJqdGkiOiJmMTc1ZjdiNy1iN2ZmLTQxM2UtYjM5Ny0yYTQyYmI3NjMxZmQiLCJpYXQiOjE1MDk1NTY2MzQsInJvbCI6ImFwaV9hY2Nlc3MiLCJpZCI6ImJlOWJmZjc5LThlNDEtNDEwYS1iN2E3LTBjOGQxNDExYjQ5YyIsIm5iZiI6MTUwOTU1NjYzNCwiZXhwIjoxNTA5NTYzODM0LCJpc3MiOiJMb2dpbkFwcCIsImF1ZCI6Imh0dHA6Ly9sb2NhbGhvc3Q6NTAwMC8ifQ.NbwKHjH8h
Cache-Control: no-cache
Postman-Token: 18e932c2-ac73-5539-60a1-04b7b981e37a
JwtIssureOptions
"JwtIssuerOptions": {
"Issuer":"LoginApp",
"Audience":"http://localhost:5000/"
}
Related
I'm trying to implement the microservice architecture. I'm using ASP.NET Core 3.1 API to implement.
I installed jwt packages ocelot and auth servers. When I try to log in, it returns 401. So, this part of my application is wrong. What is wrong with my code? These are my codes;
ocelot.json
I added the AuthenticationOptions key to the ocelot file.
"Routes": [
{
"DownstreamPathTemplate": "/api/auth/{path}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 52150
}
],
"UpstreamPathTemplate": "/identity/{path}",
"UpstreamHttpMethod": [
"Get",
"Post",
"Put",
"Delete"
],
"AuthenticationOptions": {
"AuthenticationProviderKey": "MY_SECRET_KEY",
"AllowedScopes": []
}
}
]
API Gateway Startup.cs
I implement jwt for api gateway
public void ConfigureServices(IServiceCollection services)
{
var jwtConfig = Configuration.GetSection("JWT");
var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(jwtConfig["Secret"]));
string providerKey = "MY_SECRET_KEY";
var tokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = signingKey,
ValidateIssuer = true,
ValidIssuer = jwtConfig["Issuer"],
ValidateAudience = true,
ValidAudience = jwtConfig["Audience"],
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero,
RequireExpirationTime = true,
};
services.AddAuthentication(config =>
{
config.DefaultAuthenticateScheme = providerKey;
});
services.AddAuthentication()
.AddJwtBearer(providerKey, config =>
{
config.RequireHttpsMetadata = false;
config.TokenValidationParameters = tokenValidationParameters;
});
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
builder => builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader());
});
services.AddOcelot(Configuration);
//services.AddControllers();
}
public async void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseCors("CorsPolicy");
app.UseAuthentication();
app.UseRouting();
await app.UseOcelot();
//app.UseEndpoints(endpoints =>
//{
// //endpoints.MapControllers();
//});
}
Auth Server Startup.cs
After, I set up JWT for my auth server.
public void ConfigureServices(IServiceCollection services)
{
var jwtConfig = Configuration.GetSection("JWT");
var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(jwtConfig["Secret"]));
string providerKey = "MY_SECRET_KEY";
var tokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = signingKey,
ValidateIssuer = true,
ValidIssuer = jwtConfig["Issuer"],
ValidateAudience = true,
ValidAudience = jwtConfig["Audience"],
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero,
RequireExpirationTime = true,
};
services.AddAuthentication(config =>
{
config.DefaultAuthenticateScheme = providerKey;
});
services.AddAuthentication()
.AddJwtBearer(providerKey, config =>
{
config.RequireHttpsMetadata = false;
config.TokenValidationParameters = tokenValidationParameters;
});
services.AddControllers();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseAuthentication();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
AuthController's LoginAsync Action
I can't even send requests here.
[HttpPost("login")]
public async Task<IActionResult> LoginAsync([FromForm] Login model)
{
var result = await authService.LoginAsync(model);
if (result.Response.Success)
{
return Ok(result);
}
else
{
return BadRequest(result);
}
}
This is the screenshot for the response;
I don't understand why I'm getting 401?
I think the problem is:
services.AddAuthentication()
Change your code like this:
services.AddAuthentication(option =>
{
option.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
option.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(providerKey ,option =>
{
option.RequireHttpsMetadata = false;
option.SaveToken = true;
option.TokenValidationParameters = tokenValidationParameters ;
});
I have an ASP .NET Core WebAPI and I generate a JWT token for authorization purposes but whenever I send the request I get 401 - Unauthorized.
The order of operations:
1. GET for token
2. GET for user <-- 401
I checked my token on jwt.io and it was correct.
When I remove [Authorize] attrivute everything works fine
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
IdentityModelEventSource.ShowPII = true;
var appSettingsSection = Configuration.GetSection("Jwt");
services.Configure<JwtSettings>(appSettingsSection);
var appSettings = appSettingsSection.Get<JwtSettings>();
services.AddControllers();
services.AddOptions();
services.AddAuthentication(x =>
{
x.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultSignInScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(x=>
{
x.RequireHttpsMetadata = false;
x.SaveToken = true;
x.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
{
ValidateIssuerSigningKey = true,
ValidateIssuer = true,
ValidateLifetime = true,
ValidAudience = appSettings.Issuer,
ValidIssuer = appSettings.Issuer,
ValidateAudience = false,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(appSettings.Key))
};
}
);
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
CreateToken method
public JwtDto CreateToken(string email, string role)
{
var now = DateTime.UtcNow;
var claims = new Claim[]
{
new Claim(JwtRegisteredClaimNames.Sub,email),
new Claim(ClaimTypes.Role, role),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(JwtRegisteredClaimNames.Iat,now.ToTimestamp().ToString(),ClaimValueTypes.Integer64)
};
var expires = now.AddMinutes(360);
var singingCredentails = new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_settings.Key)),SecurityAlgorithms.HmacSha256);
var jwt = new JwtSecurityToken(
issuer: _settings.Issuer,
claims: claims,
notBefore: now,
expires: expires,
signingCredentials: singingCredentails
);
var token = new JwtSecurityTokenHandler().WriteToken(jwt);
return new JwtDto
{
Token = token,
Expiry = expires.ToTimestamp()
};
}
GetToken - API
[HttpGet]
[Route("token")]
public IActionResult GetToken()
{
var token = _jwtHandler.CreateToken("test", "user");
return Json(token);
}
GetUser - API <---------- 401 error
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[HttpGet("{email}")]
public async Task<UserDto> Get(string email)
{
return await _userService.GetUserAsync(email);
}
I have come across the exact same problem and believe the issue is in the Configure() method in Startup.cs. You have the correct UseAuthentication() and UseAuthorization() calls, in the correct order, which is important, and was the problem I discovered. For you therefore I think the problem is the lack of the UseCors() call. My working Startup class is below:
public class Startup
{
private bool _isDevelopmentEnvironment = true;
public IConfiguration configuration { get; }
public Startup(IConfiguration configuration)
{
this.configuration = configuration;
}
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
// Retrieve App Settings:
var appSettingsSection = configuration.GetSection("AppSettings");
services.Configure<AppSettings>(appSettingsSection);
var appSettings = appSettingsSection.Get<AppSettings>();
// Configure JWT:
var key = Encoding.ASCII.GetBytes(appSettings.JwtSharedSecret);
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(x =>
{
x.RequireHttpsMetadata = !_isDevelopmentEnvironment;
x.SaveToken = true;
x.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = appSettings.JwtValidateIssuer,
ValidateAudience = appSettings.JwtValidateAudience,
ValidateLifetime = appSettings.JwtValidateLifetime,
ClockSkew = TimeSpan.Zero
};
});
services.AddScoped<IUserRepository, UserRepository>();
services.AddScoped<IUserService, UserService>();
services.AddScoped<IHydrator<User, UserModel>, UserModelHydrator>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
_isDevelopmentEnvironment = false;
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseRouting();
// TODO: Adjust CORS settings appropriately
app.UseCors(x => x
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader());
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
I also confirmed that both the token generation code and the Startup.cs code use the same key from application settings, I can't see how you get that in your CreateToken() method, but I assume it's from the same settings file. Hope this helps!
I'm working on migrating a web API from .net core 2 to 3.1, and having a problem with [Authorize] requerired endpoints. I'm getting 401 unauthorized even if i'm sending the authorization bearer token.
I think I need to change something in the way services are configured on startup class, but cannot figure it out.
This is my Startup.cs file:
public class Startup
{
public Startup(IWebHostEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = "OhmioWEBApi",
ValidAudience = "OhmioWEBClient",
IssuerSigningKey = JwtSecurityKey.Create("Secret_key")
};
options.Events = new JwtBearerEvents
{
OnAuthenticationFailed = context =>
{
Console.WriteLine("OnAuthenticationFailed: " + context.Exception.Message);
return Task.CompletedTask;
},
OnTokenValidated = context =>
{
Console.WriteLine("OnTokenValidated: " + context.SecurityToken);
return Task.CompletedTask;
}
};
});
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddSingleton<IConfiguration>(Configuration);
services.AddAutoMapper(typeof(MapsProfile));
EntityFrameworkConfiguration.ConfigureService(services, Configuration);
IocContainerConfiguration.ConfigureService(services);
services.AddControllers();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
As you can see the middleware for JWT token verification is in place.
Any suggestions?
Thanks!
Try to add below code snippet:
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(x =>
{
x.RequireHttpsMetadata = false;
x.SaveToken = true;
x.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = false,
ValidateAudience = false
};
});
I am implementing JWT Authorization on Asp.Net but I am having a trouble here. When I am trying to access the Dashboard/Home controller's method I am always recieving '401 Unauthorized' response. According to my research I can say that the request can not go through
[Authorize(Policy = "ApiUser")]
But when comment that statement I recieve an error here
var userId = _caller.Claims.Single(c => c.Type == "id");
Which states that sequence conatains no appropriate elements, and if I will print the
_httpContextAccessor.HttpContext.User.Claims
I basically recieve a '[]'.
Also I want you to notice that the token is
correct
I am testing the application with help of postman
I stacked on this error for two days and really rely on your help. Tell me if some additional code is needed.
Code:
Dashboard Controller:
[Authorize(Policy = "ApiUser")]
[Route("api/[controller]/[action]")]
public class DashboardController : Controller
{
private readonly ClaimsPrincipal _caller;
private readonly BackendContext _appDbContext;
private readonly IHttpContextAccessor _httpContextAccessor;
public DashboardController(UserManager<AppUser> userManager, BackendContext appDbContext, IHttpContextAccessor httpContextAccessor)
{
_caller = httpContextAccessor.HttpContext.User;
_appDbContext = appDbContext;
_httpContextAccessor = httpContextAccessor;
}
// GET api/dashboard/home
[HttpGet]
public async Task<IActionResult> Home()
{
// retrieve the user info
//HttpContext.User
//return new OkObjectResult(_httpContextAccessor.HttpContext.User.Claims);
var userId = _caller.Claims.Single(c => c.Type == "id");
var customer = await _appDbContext.Customers.Include(c => c.Identity).SingleAsync(c => c.Identity.Id == userId.Value);
return new OkObjectResult(new
{
Message = "This is secure API and user data!",
customer.Identity.FirstName,
customer.Identity.LastName,
customer.Identity.PictureUrl,
customer.Identity.FacebookId,
customer.Location,
customer.Locale,
customer.Gender
});
}
}
Startup:
public class Startup
{
private const string SecretKey = "iNivDmHLpUA223sqsfhqGbMRdRj1PVkH"; // todo: get this from somewhere secure
private readonly SymmetricSecurityKey _signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(SecretKey));
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddIdentity<IdentityUser, IdentityRole>()
.AddEntityFrameworkStores<BackendContext>()
.AddDefaultTokenProviders();
services.AddDbContext<BackendContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),
b => b.MigrationsAssembly("Backend")));
services.AddSingleton<IJwtFactory, JwtFactory>();
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("ApiUser", policy => policy.RequireClaim(Constants.Strings.JwtClaimIdentifiers.Rol, Constants.Strings.JwtClaims.ApiAccess));
});
// add identity
var builder = services.AddIdentityCore<AppUser>(o =>
{
// configure identity options
o.Password.RequireDigit = false;
o.Password.RequireLowercase = false;
o.Password.RequireUppercase = false;
o.Password.RequireNonAlphanumeric = false;
o.Password.RequiredLength = 6;
});
builder = new IdentityBuilder(builder.UserType, typeof(IdentityRole), builder.Services);
builder.AddEntityFrameworkStores<BackendContext>().AddDefaultTokenProviders();
services.AddAutoMapper();
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.TryAddSingleton<IActionContextAccessor, ActionContextAccessor>();
services.AddDbContext<BackendContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),
b => b.MigrationsAssembly("Backend")));
services.AddTransient<IStoreService, StoreService>();
services.AddMvc();//.AddFluentValidation(fv => fv.RegisterValidatorsFromAssemblyContaining<Startup>());
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseAuthentication();
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseMvc();
}
}
Constants (used in startup):
public static class Constants
{
public static class Strings
{
public static class JwtClaimIdentifiers
{
public const string Rol = "rol", Id = "id";
}
public static class JwtClaims
{
public const string ApiAccess = "api_access";
}
}
}
For your issue is caused by the mismatch configuration between token generation and validation for Issuer and Audience.
In Startup.cs, you configure ValidateIssuer = true and ValidateAudience = true, but for your provided token, there is no iss and aud.
Here are two ways for a try:
Disable to validate Issuer and Audience
var tokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false,
ValidIssuer = "Issuer",
ValidateAudience = false,
ValidAudience = "Audience",
ValidateIssuerSigningKey = true,
IssuerSigningKey = _signingKey,
RequireExpirationTime = false,
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero
};
Or, provide the Issuer and Audience while generating the token.
public IActionResult Login()
{
var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("iNivDmHLpUA223sqsfhqGbMRdRj1PVkH"));
var signinCredentials = new SigningCredentials(secretKey, SecurityAlgorithms.HmacSha256);
var tokeOptions = new JwtSecurityToken(
issuer: "Issuer",
audience: "Audience",
claims: new List<Claim>() { new Claim("rol", "api_access") },
expires: DateTime.Now.AddMinutes(25),
signingCredentials: signinCredentials
);
var tokenString = new JwtSecurityTokenHandler().WriteToken(tokeOptions);
return Ok(new { Token = tokenString });
}
Here is a working demo CoreJwt.
It has passed about 4 months since this question has been asked, but I hope it will help the future visitors, I had the same problem and it was because I had missed to add the app.UseAuthentication(); to my Configure method:
app.UseAuthentication();
//////////////////////////
app.UseHttpsRedirection();
app.UseStaticFiles();
Also I had missed to add the JwtIssuerOptions to my appsettings.json and appsettings.Development.json:
"JwtIssuerOptions": {
"Issuer": "webApi",
"Audience": "http://localhost:5000/"
},
I'm trying to implement JWT in ASP.NET Core Web API. In version 1.1.2 of JwtBearer I have this code in my Startup.cs file:
public void ConfigureServices(IServiceCollection services)
{
...
services.Configure<JwtSettings>(Configuration.GetSection("jwt"));
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
...
var jwtSettings = app.ApplicationServices.GetService<JwtSettings>();
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
AutomaticAuthenticate = true,
TokenValidationParameters = new TokenValidationParameters
{
ValidIssuer = jwtSettings.Issuer; // "http://localhost:5000"
ValidateAudience = false,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings.Key)) // some secret Key
}
});
app.UseMvc();
}
How this code should looks in JwtBearer 2.0.0?
I installed this package like this:
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
My .NET Core Version:
2.0.0
Based on the above code to transition this to dotnet core 2.0 you need to refactor as below... well adjust it as per your requirements, this is a quick answer while in transit.
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(o => {
o.Audience = Configuration.GetSection("jwt:Audience").Value;
o.Authority = Configuration.GetSection("jwt:Authority").Value;
o.RequireHttpsMetadata = Configuration.GetValue<bool>("jwt:RequireHttps");
o.Events = new JwtBearerEvents()
{
OnAuthenticationFailed = c =>
{
c.NoResult();
c.Response.StatusCode = 401;
return c.Response.WriteAsync("Invalid Token");
}
};
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
// ...
app.UseAuthentication();
// ...
app.UseMvc();
}
This could work for you:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<JwtSettings>(Configuration.GetSection("jwt"));
var provider = services.BuildServiceProvider();
var jwtSettings = provider.GetService<JwtSettings>();
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(o =>
{
o.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = jwtSettings.Issuer;
ValidateAudience = false,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings.Key)) // some secret Key
};
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
....
app.UseAuthentication();
app.UseMvc();
}